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.
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.
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.
> Optimization hinders evolution.
Still my favorite of all his epigrams.
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!
... 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).
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.