ForeverList update: Starting to implement transaction log as storage

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.

In summary:

  • 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.

Career tip: Write down what you learn each day

I started a new job a few weeks ago and one thing I’ve started to do is write down every new thing I learn each day on the job. I have a simple text file that I add to whenever I find I have to learn a new technology or engineering practice. I’m finding it has some nice benefits.

One: I’m learning a lot of new things right now. This is a good thing and writing down what I learn helps me track how much I’m learning each day. Once I slow down my learning, which will inevitably happen due to deadlines or other factors, I can re-evaluate if it’s something that’s temporary or permanent (time for a change).

Two: Writing down what I learn has led to a virtuous cycle. To maintain my learning daily pace, I’m finding that I’m seeking out things to learn. If I’m taking on a task and there’s something I don’t fully understand, I will now try to learn it more fully instead of getting by with being ignorant. It’s the old “you get what you measure.”

Three: Most practically, writing down what you learn each day will make it easier in the future when you look for a new job. When it’s time to find a new job, you have a long list of skills you’ve developed. You can turn those into appropriate bullet points for your résumé or talking points for the interview.

If you want to give this a try, just create a text file for your log. Each day, jot down the date and then when you learn something new, write one sentence describing it and move on. Don’t get into details. You just want to jot down something quick so there’s no friction to your current daily workflow. At the moment, I’m finding I’m learning about two to three new things each day in my new job. If you give this a try, let me know how it works out for you in the comments below.

ForeverList Update: File loading and saving

As mentioned the other day, I’m working on a new app. I’m calling it ForeverList for now. I’ll be posting updates to this blog as I make progress.

Well, today I added file load and save!

It took about half an hour to add. It was pretty simple to implement. All I do is serialize the tree representing the document into a JSON dictionary.* Just use JSONSerialization to get this done. Easy.

However, I then spent another half hour tracking down a bug caused by a poorly configured storyboard. (I have no idea how it got in that state.) I’d hit an exception at runtime, but other than a call stack into Cocoa, I had no way of determining what was causing the problem.

After pulling my hair out, I decided to delete the old view controller in my storyboard and add a new one, configured exactly the same way. That fixed it. 😩

I’m still seeing another exception in -[SFLList removeItem:], but it looks like another Apple bug. Argh!

Oh yeah, at one point, Xcode crashed in the middle of typing some code. This is one thing I often forget about Mac and iOS development: a lot of time is wasted dealing with issues in Xcode or Cocoa.

* I should note that the JSON format here is temporary. I’m planning on saving a journal of changes as I did with Lil Todo. That way I can allow multiple clients to modify the same document and sync them to a central file share, like Dropbox or OneDrive.

Software development: How to prioritize your work

Photo by the author

tl;dr – Work on tasks that will eliminate risk and reduce unknowns first.

Software development is a complex and unpredictable activity. Because there are a lot of moving parts, big problems may not present themselves immediately. Many technical challenges often don’t come up until other supporting work is done first. Usability issues may remain unforeseen until the bulk of an app has been written. These challenges can affect the schedule of the project if not tackled early as they can cause unnecessary re-work to be done.

Many of these challenges remain unknown simply because they are needlessly prioritized behind other work. Endeavor to constantly reduce risk by finding and completing high-risk work items first.

When breaking down your work into bigger pieces, assess the risk of each piece. Figure out what has the highest risk. These are the things that you understand the least. Ask yourself how much you know about the problem space. How many assumptions are you making? Are they valid? Are there a lot of moving parts? If so, can those parts work well together?

After coming up with a risk assessment, prioritize the highest risk items first. The goal in attacking the high risk tasks first is to learn and gather more information and then adjust your schedule, your designs, and your product goals as necessary.

Likely the biggest risk most products will have is the usefulness of the product itself. Is it something people actually want? How do you know? One way startups mitigate this huge unknown is to build a prototype (with a limited feature set and with basic UI) as soon as possible. Get it in your hands and potential customers’ hands early. You’ll likely find issues right away that you couldn’t see with static design mockups.

Another big risk is architecture. How should the product be built? If you aren’t familiar with the technical space, prototype using components as soon as possible. The goal is not to come up with a pristine architecture, but to just understand the problem space and see what is even possible with the tools and components available. Find out what the tolerances of each component are. Will it be enough for your goals? If you were planning on using open source components, do you have everything you need? The worst thing you can do here is to design at too high a level with limited knowledge of the space. Don’t commit to big decisions based on missing information.

In my experience, getting an end-to-end scenario working reveals so much. Plumbing, i.e. getting data from one place to another, is one of those things that is hard to theorize about and is only really knowable by writing code. Once you get a basic end-to-end scenario that uses most of the pieces of the stack you expect (even with prototype pieces in the middle), you will find out what components you’ll need and how to difficult or easy it is to connect them together. This will reveal more than a theoretical design ever could.

High risk work has a greater impact on the success of a product than anything else. It also means it’s harder to reverse these decisions, so it’s important to get them right earlier than later. As you complete more and more high risk work, the stability of your completion date should improve. How the final product and final software design will look should stabilize as well. Don’t let high risk and difficult-to-reverse decisions be made late in the project. Get those out of the way early!

In summary, map out what you need to do to complete your project. Figure out where the big unknowns (and big risk!) are and then prioritize those items first. Prototype as necessary to help validate your hypotheses, learn, and adjust your plan as you learn more. Repeat until you are done. Good luck!

 

These thoughts come from my own work experience, but many of the ideas weren’t obvious to me until I read Lean Software Development, so please read that for a more information.

I’m working on a new app

I was inspired recently and decided to write another app. I’m going to write a note-taking app that lets you nest notes in a hierarchical fashion and use markdown for text formatting.

I wanted to understand what challenges it might impose, so I decided to prototype some UI today.

Here’s what I’ve got so far.

After about four hours of coding, the following work:

  • Basic data type to represent a node and its children.
  • Functioning UI to view the nodes. You can select a node and view its children. As you dig deeper into a hierarchy, more and more tables are added and you can scroll left and right to view each level.
  • Editing and adding of nodes works. You can double-click a node and a modal window pops up to let you edit the text. When done, the changes are saved and the UI is updated. You can add a new node with a shortcut key.
  • Markdown formatting. I used SwiftyMarkdown to convert my markdown text into an NSAttributedString that I could display in the table view. Unfortunately, SwiftyMarkdown doesn’t build for macOS, only iOS. I hacked it quickly so that it doesn’t rely on UIFont. The hack is temporary, and I’ll likely re-do this work later and send a pull request to the author.

The big thing that doesn’t work yet is saving and loading a document. I want a working end-to-end scenario soon, so even though I’m still thinking about what I need in the document format, I’ll move forward with a simple JSON dictionary for the time being. (This file format won’t cut it if I want to sync across multiple devices. I’ll probably do something similar to what I did with Lil Todo.)

The app will be made up of nested tables, as you’d see in a UI like macOS’s Finder. Each table will contain a list of notes. Each note will use markdown for formatting. For simplicity, notes don’t have titles. They just have text. When you click on a note, you’ll see a list of additional notes to its right. These are sub-notes. This will allow you to easily create hierarchical notes, like an outline. You’ll be able to add as many sub-notes as you’d like to any note. You can also drag and drop notes around to change the hierarchy or grouping of things.

I will admit the UI is somewhat inspired by gingko, however I don’t plan on showing all the notes at a given level as they do there. (I find that a little confusing.) I’ve always been fascinated by using nesting to organize thoughts. A couple of other apps that I’ve enjoyed using that are somewhat related are MindNode and Tree. Both are simple and beautiful apps.

Some other features that I plan for this app:

  • Images as notes. You’ll be able to drag an image as a note anywhere. To keep the UI simple, I’m not planning on “embedding” images within the text. They’ll simply be treated as other notes.
  • Cloud file sync. I’ll support Dropbox again and possible other cloud file sync engines. I don’t plan on writing a custom service for this, but the app will support single-user editing a document across multiple devices.
  • Views. It should be possible to collect all notes that have to-do items in them and present them all the to-dos in a massive list. It should also be possible to collect all notes that have a hashtag in them and also present them in a massive list. These will be treated as “views” that allow you to look at your data in a different way.

My plan for this app is to write it as quickly as possible, get an MVP working, and ship it to the Mac App Store. It’s March 5, 2017, so let’s see how quickly I can do that. My second goal is also to write up development notes on this blog to share some of the techniques I use to write software.

If you got this far, thanks for reading! Be sure to also follow me on twitter for updates.