I have an 8 year old app that reminds me a lot of this article.
Something that's worked really well for me was that I created a plugin feature and most new features are actually plugins. This lets me add capabilities without touching or adding logic to the core code.
Last night I added SQLite support as a plugin. 2 code files and one is unit tests. https://github.com/jmathai/elodie/pull/443/files
I don't know if this is the best approach but it's worked better than others in my 20+ years of writing software.
> Novelty and optimization are the enemy of durable, long term code.
This sums up so much of what makes software rot in seemingly short time horizons.
Oh, and 3rd party SDKs that he mentioned.
Limit complexity and 3rd party SDKs like the plague.
Taylor, I really enjoyed this post, and I shared it with my engineering team and also group chats.
At Wyndly, we're a software-enabled allergy immunotherapy practice (https://www.wyndly.com/pages/immunotherapy). I have a background in software engineering, and I had to learn that code wasn't always the solution. Better code doesn't mean better business outcomes for us! Sometimes I say "Every line of code is a liability!", because it's now something a small team has to support forever.
Your three bullets on how to build are something I agree with so much! Arguably, this is something everyone outside of an at-scale product should build while finding product-market fit and growth channels:
- Focus on building simple solutions that solve real, urgent user problems, in well-worn ways.
- Use battle-tested software and platforms that are stable and don’t change too much over time.
- Only integrate with third parties when it’s absolutely necessary for solving those real, urgent problems.
Thank you for sharing!
What a great article. When he mentions that Facebook and Dropbox were launching their own similar apps, it would be fun if in the end he would end up acquiring all of them, Pinboard style.
Integration tests that fire up a local server are not that unusual I find. I don't think there is anything unusual or "wrong" about that.
... But if you are counting how long integration tests take to run in single-digit minutes then either your app is really small/simple or your integration coverage is low! :)
I've worked on "state of the art" frontends at BigCos where integration/end-to-end tests are sharded across perhaps 10 test server instances ("local" in spirit, in reality technically not on the workstation), and even then it takes 20+ minutes to execute. They typically have to execute separately from the usual unit tests etc (which run automatically as part of the pre-push CD set up).
What do you mean with running App Engine locally? There used to be a local development server, but that did not survive the 2to3 transition. GCP does ship a Datastore and a PubSub emulator, but no Cloud Storage for example (someone wrote this one [1], which sort-of works but it does not behave 1:1 like GCS, so ironically my tests have to work around bugs in the emulator...).
I have over 50 ios apps that are over 10 years. It is amazing how competitors come and go.
Yet another good example of why you should minimise 3rd party dependencies as much as possible if you want to minimise long term maintenance costs.
If you can’t avoid some dependencies then put a firewall between your code and those dependencies. The firewall shields your code from changes to the dependencies.
Basically:
Your code -> Interface -> Adapter -> 3rd party dependency.
So your code depends on the interface not the 3rd party code. And the adapter implements your interface by mapping it to the 3rd party dependency.
I have 10 year old android apps. Granted mine have few users and were never successful.
>What’s changed the least? The “boring” technology. Postgres and Redis required zero hijinks to keep running. Even Django itself caused very little trouble when I upgraded from Django 1.5 to Django 4.0 in June 2022 — I barely had to touch my Django views! Most of the Django changes were in configuration and routing, and the most difficult single thing was migrating ancient Django 1.5 session data to the modern Django 4.0 format so users wouldn’t get logged out during the migration.
The older I get, the more I appreciate the value of reliable and relatively unchanging software components. Not that there isn't a place for innovation, but there's also a place for good things that endure.