Quick update on the ForeverList project: Today I spent two hours and implemented basic loading and storing of the ForeverList document as a transaction log.
First of all, its worth noting what “document” in ForeverList will be. ForeverList lets you create lists of notes, where each note is made up of text and possibly more child notes. This way, you can organize your notes hierarchically.
Now onto the transaction log: When you edit a ForeverList document, ForeverList will store individual changes as transactions in a log. A transaction is simply a description of a change to the document. For instance, if you create a new note, the app will store an entry in the log that says “user created a new note and here is the text they entered”. If you go and change the text in that note later, it will create a log entry that says “user changed the text for this note to ‘blah blah blah'”.
When the user saves the document, which is made up of many notes, the app will simply store this log of changes and not the notes themselves. If you close the app and later re-open the document, the app will load this log of changes and play it back from start to finish to re-create the document and its notes.
Why do it this way instead of storing the document’s list of notes verbatim? Well, using transaction logs will allow a document to be edited by multiple devices. That is, it will let you open up the document on multiple Macs or iPhones (once I write that version of the app) because each device will get its own transaction log. When you save from that device, it will only write the changes that were made from that device. However, when you open a file, we’ll take all the changes made from all devices and merge them into a mega log file and play back all the changes in chronological order. This is basically how I implemented the storage for Lil Todo.
Sharing a single file across multiple devices requires a lot of coordination. If your Mac and iPhone are editing at the same time, how do you let them save different copies of the same file? How do you resolve conflicts if one of them saves first and the other one notices? By breaking down the changes into a log with timestamps, we avoid coordination by forcing each device to write to its own file (nobody else is allowed to write to it!) and we avoid conflicts by letting the latest change “win”.
One important bit about how the document is stored: the document is actually going to be a directory that contains multiple files, i.e. all the transaction logs from all devices. (In the future, when you drag and drop images into the app, I’ll also store the images in this folder as well!) The way I’m handling this is via Document Packages on the Mac. Cocoa on the Mac allows you to write a Document-based app where instead of saving to a specific file, you provide a “document package” object which describes a list of files that will be written to disk instead of a single one.
At this point, I don’t have cross-device syncing support yet. In the future, you’ll be able to use a cloud storage provider like Dropbox or OneDrive. For now, what you will be able to do is save a ForeverList document to something like Dropbox and you’ll still be able to open and edit that document from multiple clients because each client will only save to its own transaction logs. If they all shared the same file, however, we would have to worry about different file versions and synchronizing access to the file and potential conflicts in the changes. Dropbox will take care of syncing the individual transaction log contents for you.
- Each device will record each change that is made to a document and save those changes to its own transaction log.
- The ForeverList “document” will simply be a folder that contains multiple transaction logs, one from each device.
- When ForeverList opens a document, it will open up the folder, collect all the transaction logs from all devices and then merge them into a single transaction log, which it will then “play” from start to finish to reconstruct the document.