Ask HN: Have you ever inherited a codebase that you liked?
It seems everyone always complains about the legacy codebase they inherited. I can't think of a single time I've heard someone speak positively of an inherited codebase. I'd love to hear from anyone who actually liked a legacy codebase that they didn't originally author. What made it great? What lessons / takeaways are there for the rest of us?
20 comments
[ 3.2 ms ] story [ 61.9 ms ] threadI have inherited a couple of 10 years+ codebases at my current place, I would say that usually the best ones have small functions that are well documented instead of crazy abstractions. They also were built without trying to be too clever.
They use the bare minimum of the language to get the job done and do one thing only and well.
Some other code bases are much harder to grasp .. usually abusing abstractions everywhere or using libraries / programming constructs that aren’t widespread.
One that I despise is a huge asynchronous Python application built years ago with twisted.. nothing feels pythonic and it’s so hard to follow the flow of the program.
Colleague of mine once said it nicely:
I started writing simple code, then I gained experience and started writing sexy complex code, then I gained more experience and now I write simple code again.
“Who wrote this sh!t?!?” >git blame Oh, it was me... well I’m sure there’s a good explanation.
It was a relatively straightforward rails site written by a person who didn't break any norms. I knew right where everything was before I started. It was quite nice, and then I probably ruined it.
- A working CI pipeline.
- Comprehensive tests.
- Enforced linting/formatting.
- A script (or at least documentation) to set up a dev env from scratch (including resetting it if it already exists).
- Documentation of things which would take days or weeks to discover when working without the original developers, such as high-level trade-offs, code style which is not enforceable using linting (such as "Use Foo.frobnicate rather than the built-in frobnicator because …") references to issue trackers, former non-committing project-related people such as business analysts, separate documentation, credentials etc.
That said, I keep getting more and more picky about what it means to have a good code base, so in a few years I'm sure this list will be woefully incomplete.
- Use natural in-repo CI configuration like GitLab and Travis. That way a fork of the project can easily establish an identical pipeline. I can't imagine going back to Jenkins or the like at this point, where the CI pipeline is this massive snowflake waiting to break down, and always being out of sync with the code.
- The current code base has 97% coverage which is verified by the CI pipeline. I'll reiterate the old trope about this making the development faster, in no small part because we can do fearless refactoring.
- Linters and formatters check the style pre-commit (only changed files) and in CI (all files).
- I run a script nightly to reset my dev env completely. It + some documented configuration is all a new dev needs to get started.
- Keeping the documentation in the repo makes sure that every change is peer reviewed. That not only sets a minimum bar for the quality but also makes sure at least one other person has already read it once it's available to everyone.
Customer supplied some code that I had to incorporate into a new JEE app (actually J2EE back then).
I liked that code because it was just way cleverer than anything I ever expected to find in an enterprise Java app. It implemented a trie to return a list of partial recordings to make a full sentence (which was the input).
It was space and time efficient, but also extremely clear, logical, and easy to incorporate into our code base.
And best of all I was able to use those ideas to solve a similar problem in the next project.
Relational database schema is the bedrock foundation of a good codebase (for business apps especially)
I inherited overengineered ones a few times and it's terrible. There's the Chesterton's Fence to be careful of, where some thing seemed pointless but fenced off an obscure bug. The pre-Kotlin Android era also had a lot of hacks to reduce boilerplate, which ended up being a tradeoff between spending 1/3 of your time dealing with easily fixed dumb bugs from copypasted code, or spending 1/3 of your time dealing with complex bugs from testing issues, code that reduced boilerplate, old things that were deprecated in new APIs, and so on.
Twice no. One was a massive in-house project that had evolved over the years. There was a former developer, but he was not very good, and only wanted to add more bells and whistles. He got frustrated with my efforts to document the code and left. It was used to help test other code, but was the most horrid thing.
Second was 5 years ago, person left, and left literally no documentation. We had a weeks overlap, and he demonstrated the code, but in the thousands of lines of code there were a handful of comments that just had the date and his initials.
For me I need to be able to understand what the intent was of the code. Then I can either debug the indent (i.e. bad logical thinking), or implementation (not coded to do what you want).