There are a few concepts/principles in software engineering that are over-emphasised and prioritised without enough actual thinking.
- Time to first byte
- A really amazing to read commit history
Teams will introduce elaborate software development process, stop all conversations & thinking, bring weird and wonderful tech choices all to accommodate these things.
They do have some value but people love to obsess over them without ever thinking about the costs.
Time to first byte
This is very important, we want our websites to respond quickly when our user first reaches them.
- Build an SPA with a framework released last month so that we can continue to shovel 12mb of useless resources at a user.
- Website still performs terribly but at least something appears quickly!
- Endless rewrites, messing around with build/packaging tools
What you should do
The performance of your website is more complicated than just one metric and by over-emphasising time to first byte you could be harming everything else.
- Total number of requests
- Size of resources
- CPU impact of executing JS
- How cacheable it is
DRY (don't repeat yourself) is when you take some repeated code and refactor it into a function/class/interface/whatever so it can be re-used elsewhere.
Repeating code is annoying and can be wasteful. If you want to fix a bug and you have repeated code that would be sad.
- Weird Frankenstein functions/classes with optional arguments or boolean flags passed in to concepts that are loosely related, but are not really.
- INTENSE COUPLING
What you should do
- If a concept is shared by more than 2 things, you can probably safely refactor. Just hold off. Someone clever said bad abstractions are worse than none. Wait until it is clear that there is something really there to DRY up.
- If you end up adding flags to functions to make them behave differently, that is a red-flag.
- When making a simple change, do lots of tests fail? Lots of compilation problems? That's usually an indicator of tight-couping and that is often born from engineers worrying too much about making DRY code.
- Acknowledge that making re-usable code is difficult and risky. Multiply this by 10 for re-usable services.
A really amazing to read commit history
We want it so that people can look at a git history to have an idea of the motivations behind the changes in a project.
We will typically not accept changes directly into master but instead insist on carefully crafted pull requests that get evaluated before being merged.
- Actually shipping software becomes an insane discussion full of bike-shedding. Pull requests lasting days, weeks for the most trivial of changes that should've been released yesterday.
- Job ads still hilariously saying that they practice continuous integration, meanwhile the devs have a tremendous time dealing with merge conflicts or just flat-out scared to change the code because of competing pull requests.
- Still no one has any actual hope of understanding the code base just from looking at the git history, because of course you cant. You understand a code base by reading it and changing it.
What you should do
- Good, descriptive tests.
- Pair programming.
- Try out ADRs.
- Actually talk to each other, build a team.
There are caveats to this. For a distributed team pull requests make sense as they aid conversations etc. You acknowledge that the constraints on this kind of approach means you will iterate slower than other teams.
If you are in a colocated team who want to build and iterate on a product quickly this kind of approach is extremely wasteful. Just push to master as quickly as you can and talk to each other.
Top comments (12)
Anyway, just a few words on the 3 points
To be super clear (if we're all off quoting Wikipedia YAWN)
Where 'emic' means within the social group.
What Chris is saying (I think) is that the social group of developers attribute to the three objects (DRY, time to first byte, and 'clean' commit histories) inherent supernatural powers which they have in and of themselves.
If you are sexually aroused in any way by having a clean commit history, seek help.
This is not really the point I'm trying to make.
If you are fetishising time to first byte then you are prioritising performance. The point is that you should not be prioritising that above everything else in respect to performance.
I wouldn't get too caught up about the definition of "fetish".
Very good article! I really like your advice on DRY coding. I find myself overthinking when I put too much focus on DRY.
I was about to create some overly complicated DRY solution to two very similar functions today. But thinking about this post again, i decided against it. 🤗
See the other comments, fetish is appropriate (if exaggerated) :)
I'm intrigued by the build-a-framework fetish, which - unlike the others you describe - isn't quite based on any useful principles.
What am I talking about? Let's say that as a .NET developer I need to store some data in some Azure tables. My tendency will be to create abstractions that aren't specific to Azure at all, and then in the implementation I'll use the classes Microsoft provides. The same is true for pretty much anything. Sometimes someone produces a really great library that simplifies the use of another, and if it seems really helpful then I'll use it.
The fetish I see is that developers immediately want to start building pointless, unnecessary "frameworks" to wrap existing classes, and then they want everyone else to use them for the sake of consistency. (This is much worse when it's a developer who can enforce it.) So now if I want to use an Azure table I have to use their weird, buggy wrapper class in a library named CompanyName.Frameworks.Storage.AzureTableStorage. Existing code is littered with dependencies on
IMySpecialAzureTableStorageWrapperClasswhich a) isn't an abstraction because it can't represent anything other than Azure table storage, and b) hides or confuses the methods I need on the underlying classes. The solution? Add to the problem by modifying the wrapper. (I'm sorry, I meant "framework.")
It forces developers to learn someone else's bad proprietary code while denying the opportunity to learn the underlying API. In return it adds nothing except bugs and overhead.
It also gives some developers an opportunity to appear productive because they're constantly writing wrappers for stuff that doesn't need to be wrapped, and the fact that it's used everywhere creates the illusion that it serves a purpose.
The conflation was accidental on my part. The main point I was trying to drive was the over-emphasis on time to first byte can end up with teams ignoring other factors (like number of resources to fetch) and also the proposed solutions to improve time to first byte can also hurt the other performance metrics I mentioned.
Thanks for sharing! Regarding DRY, were you referring to this article by Sandi Metz? sandimetz.com/blog/2016/1/20/the-w...