Software Development Principles
These are things that I believe I have learned over the course of my career, which so far has mostly consisted of working as a Python backend developer. Some of it I have been convinced of by reading or watching things online. Other things I have concluded based on my own experience.
- Consider building a monolith. Scaling vertically is valid and gets you far. Only reach for microservices if there is a concrete need, and only do it for that concrete need. Network calls, APIs and serialization between services will be your death. Further reading: https://benhoyt.com/writings/the-small-web-is-beautiful/#small-architectures-not-microservices
- SQLite is awesome. Consider using it before deciding to use a full DBMS. What you lose in lack of horizontal scalability, you main gain many times over just by avoiding the network and auth. Further reading: https://charlesleifer.com/blog/five-reasons-you-should-use-sqlite-in-2016/
- Python may be slow, but the network is even slower. Optimize your network calls first.
- Deploy a thing that is as self-contained as possible. The less self-contained your deliverable, the more valuable it is to use a container. In order of preference:
- Statically linked executable.
- Dynamically linked executable.
- Literally anything.
- Python (deploying Python is a mess).
- Prefer statically typed, performant languages that handle dependencies well (Rust).
- Avoid proprietary features of cloud services. Prefer simple container runtimes and/or Linux VMs.
- Prefer open source.
- Dependencies:
- Adopt dependencies conservatively.
- Pin the exact versions of all your dependencies (every single package in the dependency tree).
- Semantic versioning is overrated (and will not save you). Your dependencies pinned by MAJOR or MINOR versions will break. As far as your own code is concerned, your colleagues will just keep bumping the PATCH number regardless of the change, because they don’t actually care, and perhaps rightly so.
- Consider separating application code, deployment config and documentation in different repositories. A config change in a test environment, or a documentation change, should not increment the version of the application. If your project does not use versioned releases, this might not matter.
- Control the data models you expose in your API. Do not expose the internal representation directly; use an abstraction even if it initially is identical. Absolutely do not expose someone else’s data model unless you make it very clear that you take no responsibility for it.
- Don’t over-complicate your VCS branching strategy. Just keep it mostly linear, do what makes sense in the moment, and use tags to mark versions if applicable. Naming is more important. GitFlow is insane.
- Testing is good, but
- Avoid mocking where possible.
- Avoid writing tests that just re-implement your code.
- Test-driven development is overrated.
- Profile before optimizing, so that you optimize the right thing.
- “Agile” is an adjective, not a noun. If someone sells you “agile” as a noun (e.g. Scrum) and you buy it, you have already failed at agile software development. Agile is Dead (video).
- No test environment is equivalent to production.
- Premature abstraction is a greater evil that premature optimization.
- Overly short functions are worse than long functions, because they obfuscate the flow of the program. Just avoid repetition.