May 2, 2021
I like to highlight key points.
- Requirement: Edit image, continue to work on it in another device, sequential editing in different device. Not collaborative editing
- My thinking, distributed cache, sync, image edit in detail, and version control.
Facebook | Onsite 2021 | System Design | Design image editing
Last Edit: February 21, 2021 9:20 PM
3.7K VIEWS
Design a mobile application where user can edit image (add some effects like Instragram).
Follow up user should be able to continue working on another device. Not a collaborative editing, just continue from the same point.
Solution
I proposed to store image (S3) and actions (nosql) separatly. Each editing is a sorted coollection of actions: {id, actionType=Crop/Blur, actionData=...}
For follow up: when user opens application the request with the last action id is sent to the server. There is a Redis with all active sessions. If there is already one -> send back a collection of new actions and apply at the new device, in the same time the old session should be blocked.
I was completely confused by this question and how to tackle this, have never seen something like continue of work. Probably there is some name of this pattern. Any ideas what I've missed?
This round was the worst performance and the reason of a reject.
Last Edit: March 8, 2021 9:00 AM
My take on the problem, feel free to criticize.
- As this is image editing application, I assume this is offline first application.
- I'm not expert in Image processing, but for the sake of simplicity let's assume every interaction(adding effect, increasing brightness) creates new layer that I can undo and redo.
- Before I go ahead and start designing, we need to get clarity on how to resolve conflicts. If the user is editing the image from 2 devices, we will have to handle conflicts(like google docs). To keep this simple lets go ahead with approach where the latest change wins. Do remember that we might loose some data with this approach.
- The changes to the image can be synced periodically to the server. As there could be lot of changes, the client and server should have a commit mechanism where only diff is sent to the server.(conflicts can be resolved during commit).
- simple schema to store the image - {
"id": "xyz",
"imageUrl": "someS3",
"version": 8,
"edits":["filter", "brightness"]
} - sample API -> PATCH -> fb.com/image/xyz { version:8, edits : [array of changes] }
response of the request will be the new version number. - When the changes are completed and posted the image service can generate a final image with edits and cache the image.
Assumption the image is already stored in the cloud and the design of that is in place.
- When there is an update/edit, the client can be intelligent and send the updates alone instead of the entire image to the server which would save bandwidth.
- updateImage(api_dev_key, user_id, image_id, modifications); response will 2XX/4XX/5XX
- We can estimate how many of these updates will be done and come up with some numbers.
- Once the image is updated, we will have some kinda notification server in place which would inform us who are the subscribers to it and push the update to those devices too(again only the update)
Also, since this deals with images and processing of it, I would have a queue between the web server and the application server which will write/modify the existing image location.
One more feature we can provided as part of it it snapshot the previous version too in case user is interested.
Follow-up:
The moment the app in the client makes any changes, keep posting(periodically checkpoint) it in some db/cache (Maybe set a timer for this and expire/if that's a req) store the image in S3/cache(LRU) and do not modify the original copy of it. We can push this to the other devices and let them take it from there.
I think there is a need to discuss ACID property as two clients can be modifying the image together. This kind of pushes from multiple devices may cause trouble in our system as we may overwrite each device with other content.
I am new to system design and be gentle on me as this is just my thoughts.
just have questions and considering: online edit or download and local edit then upload? generate a new image or replace the original? support undo? how big is the image? how to define the same point, edit and commit by manual or support auto-commit? what is period for autocommit? how to handle the offline or without network? if online edit, u will also need a local copy, but maybe not the original size of image, also that mean both app and server need to define a common set of operations, so you can just send the operation instead of the image. overall maybe can start from download, edit in local and upload to replace, then further option is to base on edit operation sync between device and server???
Last Edit: March 20, 2021 8:37 PM
Distributed locking using fencing tokens which you have already covered can make sure only one device has the session.
I think you could have asked some clarifying questions here.
When do we merge the layers? onSave or onRead? Push model or pull model. You can use the same collections and apply edits on the last checkpoint.
Are we looking at cross-continental traffic? (changes take time to propagate) Cross DC traffic adds a lot of latency as the data is located on another continent.
You came up with a good model of raw images and editing layers. Raw images can be distributed globally using a CDN and get edits from a database.
Follow up: Since you have a single session and most probably follow up again on multiple sessions? Does eventually consistency still hold true? You cannot have last-writer win scenarios. Because I don't think layers are associative or commutative or idempotent (non-CRDT).
Is Edit processing on-device or on-server? If on-device depending on device capabilities, your image may look very different.
Can you support checkpointing? Merge a few edits in order and create a new image and distribute it?
On Save? Can it be treated as a new image or replace the older image? What is the average time difference between the two sessions if it not collaborative? CDN take time to propagate.
Sharding for a lot of users - hash-based partitioning or range-based partitioning?
Versioning - treating edits as transient till they are saved - do we refresh them on getting a session from a database.
April 6, 2021 10:35 PM
was this for a mobile role or a generalist role?
March 17, 2021 3:17 AM
How is this different than just designing Dropbox? Only for pictures instead of documents?
Last Edit: March 15, 2021 8:25 PM
I think the question is designed to be vague is asking for clarification questions. These are what I'd ask (to the follow up):
- When the user opens application, would it create a new session right away?
- What does it mean by old session should be blocked? How does the user know that the session is blocked? Should we display a popup right away when the application is opened from another device? Or maybe change the color of the screen to grey scale? Or should we display a popup the next time the user attempts to make edits on the old device?
- If the use close the application and reopen from the old device, would it regain the session?
- How do we decide that a session is "active"? Do we set TTL? Do we have socket connection between the phone and the server? Do we have some HTTP pulling?
March 11, 2021 3:29 PM
Are you applying for a mobile role? Is this product design round or system design round? Sounds strange to me that they ask to design a mobile app for a system design round.
Last Edit: February 25, 2021 11:11 AM
Thank you. Can you please tell me how many YOE you have?
I will have an onsite interview in a few weeks (university grad) and they said I will have such things, I wonder how different it will be from someone with more YOE.
February 21, 2021 11:33 PM
could you share location and level as well?
February 22, 2021 5:31 PM
Sure, Seattle and E5