I am done with my latest project.
“Noated” (Noted was taken…) is live and available to install, and I’m feeling reflective. (note I have since removed it from the App Store as I didn’t have time to maintain the project 🙁
I started out, a month and a half ago trying to make:
“A cross platform notes application, a la Mac notes app, but one that works on Mac, Windows, Android and IOS“
I ended up with:
“A cross platform notes application, a la Mac notes app, but one that works on Mac, Windows, and IOS“
So no Android… yet.
Given that I personally use Windows, IOS and Mac, I’m pretty happy though.
See it in action here!
I was feeling a bit mopey this morning as the realisation that my distracting/all consuming side project is over and I need to start thinking about paid work again.
So I decided to get a bit of closure and do a debrief of the project.
What were my goals?
To try something new.
To expose myself to problems I haven’t encountered professionally, and hopefully get a more rounded view of the development process.
What did I achieve
Most, but not all of my goals. I got a note taking app which largely fulfils my personal requirements for a note taking app, and I did it it a reasonable amount of time.
RIP Android client…
What did I learn?
A big part of why I did this project, was to expose myself to problem spaces outside of my usual domain (frontend, specifically single page applications).
In this respect it was very successful.
I gained a working knowledge of Swift, SwiftUI, real time streaming protocols (via Socket.IO) and OAuth 2.0.
I learnt that making networked apps which can work offline as well is hard.
I was also forced to figure out how to actually deploy/distribute desktop and mobile applications. In this case I ended up using the Apple App Store for the mobile app, and I hosted the installer for the MacOS desktop client on GitHub, using their Large File Storage solution. Because I wanted to make it possible for other people to install my app, I had to notarise the Mac installer, which I managed with the help of this excellent tutorial:
As I got closer to deploying the app, and was faced with the reality of random people being able to install my app, I realised I would need multiple environments for my database, server and Identity Provider stuff.
This forced me to figure out things I would never have thought about such as how to use environment variables in an IOS application via Xcode.
The thing I found most enjoyable about the whole process, was that I didn’t start with a list of technologies I wanted to use, rather I started with what I wanted to build, namely a note taking application, accessible on multiple platforms, that could be used offline and online, and synced between devices.
This meant that at every step, my technology choices were driven by what would be the best option for building the solution quickly and stably, not by what was the hot new thing.
It felt like I was exploring uncharted new territories, and relying on my prior knowledge and Google-fu, to make it through the project unscathed.
So while I did get exposed to problems which will probably be useful to have grappled with in my professional life (mainly Auth/Identity stuff, and Electron), the main thing I gained from this project was a new confidence that I can tackle things from (sort of) first principles, and that I can build things to satisfy a user requirement, using whichever technology makes sense to use.
Skip the tests!
Controversially, one of the things I learnt was that for personal projects, especially when you are still designing the system, it can make sense to skip the automated/unit testing…
This isn’t something I expected, as I am fully sold on the benefits of automated, unit and integration tests, and am normally the guy at work that goes above and beyond to prove that his code works, and is robust.
However, I think given the speed at which I was iterating and changing major system design choices, a heavy and rigid set of unit tests would have slowed me down too much, and potentially caused me to run out of steam.
A big source of motivation during this project was the visible progress that was being made on the application. Anything which got in the way of that would be problematic for me.
I have a bunch of projects I have started where I have spent hours/days setting up the perfect set of integration and unit tests, and agonising over how to incorporate CI/CD into my workflow.
These projects never went anywhere… so yeah, one of the big findings was to be a bit sloppy about unit testing. Who knew!?!
Put your ugly baby out into the world as soon as you can
Over the course of the project, I got quite attached to my baby, and nervous about showing it to other people, lest they not understand, or worse, break it.
Fortunately I was able to overcome that fear, and as soon as I had something I could put on the App Store, I did it.
I knew there were bugs in the product, and things I wanted to change, but I released it anyway.
This turned out to be a good decision for a number of reasons.
Firstly, getting apps accepted onto the App Store is not straightforward… I spend a large part of this week doing boring admin-ey things like setting up privacy policies, adding login options (Sign in with apple, obviously), and a bunch of other really dull things that take time.
Each fix meant another half a day delay, and had I tried to get the app locally perfect, I wouldn’t have known any of this.
Secondly, my friends broke my baby, in ways I couldn’t have anticipated.
These breakages again gave me new insights into what was worth spending time on, and made my product more robust.
It still hurt, but it was worth letting my fledgeling and ugly app out into the world to fend for itself.
Iterations are good!
While I didn’t go the whole hog and set up a CD pipeline or a monorepo, or any of the other things which I think are worth doing in a larger team, but take a lot of time to set up, I did use Heroku.
Heroku makes it very easy to quickly make changes to your deployed backend, and roll them back if they break things. This allowed me to move very quickly, and to iterate.
I wrote some really shit code to get the initial clients up and running.
A lot of this code got thrown away, and I actually started both the desktop and mobile applications from scratch halfway through the development process.
This, again was a good idea.
It meant I proved my ideas would work very quickly, with some very bad code, and then could build a more robust version, taking the bits which were good from the prototype.
Know your limits
After getting one client working (IOS), I went client mad, building clients for Mac, Windows, Linux and Android in one hectic week.
This was fantastic fun, and made me feel like a wizard.
Unfortunately, the following week I realised that I needed to make some pretty wide reaching changes to the underlying notes protocol…
The clients themselves were also pretty bug infested, as I had really rushed to hack them together.
This meant that I spent a few days scrabbling between clients, patching holes and trying to update them to the new protocol.
Thankfully, I realised that in order to actually build a proper solution, I needed to scale back a bit.
So I killed the Android and Desktop apps, and spent a week just focused on getting the IOS application working as well as possible, and ironing out issues in the server/notes protocol.
While this did hurt, as I was admitting I couldn’t do something, it meant that the final product was much better, and also meant that when it came time to re-animate the desktop application, I was much clearer on how a client for this new multi-notes protocol should work, and it was actually very simple.
Trying to make things you don’t know how to make is a lot of fun.
I really have loved this project, and I actually finished it.
For me this is huge. Generally I start things, lots of things, but I do not finish them.
I hope that this will be the start of my life as a prolific finisher of things. I guess we will see.
If you want to see the (now defunct 🙁 ) code, look here: