When I first picked up Software Engineering at Google I thought it was another one of those FAANG books full of lessons that make no sense at human scale. I was surprised, the lessons apply to teams as small as 5.
This is a "good shit stays" recap. The lessons that stick with you a few weeks after reading.
The difference between Software Engineering and Programming is at the core of this book. Titus Winters, author of the first chapter, finally made it click for me.
Software engineering is programming over time
Programming is about writing code. You take a task and write code to solve it.
Software engineering is when you take that piece of code and consider:
- How will this task evolve?
- How will this code adapt to those changes?
- What does this code encourage others to do?
- How does this code encourage other programmers to use it?
- How will I understand this code in 5 months?
- How will a busy team member jumping around grok this?
- What happens when the business becomes bigger?
- When will this code stop being good enough?
- How does it scale?
- How does it generalize?
- What hidden dependencies are there?
That's engineering 👉 considering the long-term effects of your code. Both direct and indirect.
You always face the underlying concern of "What's the expected life span of this code?". How you approach a black friday marketing site is different from how you approach your company's payment system.
If you liked it you should've put a test on it
When you're small, coordination is easy. When you're big, anyone might touch your code.
Solo programmers on small projects don't need lots of tests. The whole thing fits in your head. You know how it works.
As the system grows, you start to forget. Add a feature, fix a bug, part of the system you didn't even touch breaks. 🤨
Part of the problem is Hyrum's Law. As engineers join your project, they will find a way to make it work. That's a threat 😉
Any observable behavior, documented or not, supported or not, will be relied upon by someone.
You fix a bug ... Joe from billing relied on that bug for his code to work. 💩
The Beyonce rule says that if Joe liked that bug, he shoulda put a test on it. When you fix the bug, his test breaks, and you say "Oh shit, gotta fix Joe's code too".
And because Joe put tests on everything he likes about his code, you can go fix it without understanding all the gnarly details.
The earlier you find a mistake, the easier it is to fix.
Static analysis runs in your editor. Finds typos, incorrect function calls, autocompletes code.
Unit tests take a few seconds to verify your code does what you think it does. Like a checksum.
Integration tests take a few minutes to validate your system works. May catch fun edge cases.
Code review takes a few hours to validate you're following standard norms and practices of your team. Great way to share knowledge and learn from others.
QA takes a few hours or days to ensure everything works together as expected.
Users in production will find everything and expose you to edge cases you never thought possible.
The later you go in this sequence, the harder to recover from an error.
Scaling an organization is a lot like scaling a software system. How many resources does it take to support a new engineer?
Take production deploys, for example. How much work is it to combine everyone's contributions into a new release? At Google they measure velocity in commits per second.
What about code reviews?
Explaining codebase norms to 1 engineer is easier than 10. If 5 engineers join every quarter, can you keep up? What about 5 per week?
You're in trouble when overhead grows faster than engineering. Automation helps.
Code formatters, linters, codemods, continuous integration pipelines ... anything you can use to take work off people's plates. Many tasks are more mechanical than you think.
Sometimes if you make things less flexible, take control away from your engineers, you can automate the whole thing. Deploys and server config are a great example.
Less flexibility, more automation, easier codebase.
Large sections of Software Engineering at Google are devoted to automated testing. It's the only way you can scale to an organization of that size.
The part that stuck with me was a hunch I've had for a while 👉 stubs and mocks are bad.
Your tests are only as good as your mocks. They hide the true behavior of your system, drift away from reality, and take a lot of effort to maintain.
After all that, you can't even trust your tests. Like that time I had perfectly passing unit tests, deployed to staging, and realized my code relied on a database column that doesn't exist.
But it worked with my mocked database 🙃
Google recommends using fakes instead. Simplified implementations of the real thing maintained by the same team for API parity.
Use integration tests when possible.
A small release is easier to manage. A small release is easier to revert. A small release is easier to understand.
Weekly at slowest. Daily is great. Hourly is dreamy. Minutely is ... that's for large companies :D
The bigger the change, the harder to figure out which commit or feature broke production. Small changes make it obvious.
Use automation to make it painless.
Same deal as releases. The smaller the change, the easier to manage.
Upgrading from 4.3.7 to 4.3.8 is no big deal. Going from 4.3.7 to 4.4.0 might require a few changes. You can run around and update.
But going from 4.3.7 to 4.9.0 is going to be a pain. Even if every intermediate version was backwards compatible, there's no telling how far it drifted.
When you jump multiple major versions, prepare for a world of pain. Last time I attempted a project like that, we abandoned after 2 weeks. Not worth it. 😅
But a small update? You can do that in an afternoon.
Keep up to date. It's counter-intuitive but it works. Straight from The Theory of Constraints
Hand-in-hand with keeping your code up to date is how.
You can upgrade a dependency or a piece of code or make a function deprecated. Then tell everyone "Hey please upgrade".
You have to do it for them. It's the fastest way. Get into their code and make the update.
You're the expert on what needs to happen, you'll do it fast. Everyone else has to grok the change, find time in their schedule, ...
And if you have time, read the book. I liked it more than I thought.
Get promoted, earn a bigger salary, work for top companies
Getting that senior title is easy. Just stick around. Being a true senior takes a new way of thinking. Do you have it?
Get a free chapter from the Senior Engineer Mindset book and a sample audiobook chapter, followed by a Senior Mindset 101 email course.
You'll get insights to apply at your work right away.
Senior Mindset Book
Get promoted, earn a bigger salary, work for top companiesLearn more
Have a burning question that you think I can answer? Hit me up on twitter and I'll do my best.
Who am I and who do I help? I'm Swizec Teller and I turn coders into engineers with "Raw and honest from the heart!" writing. No bullshit. Real insights into the career and skills of a modern software engineer.
Want to become a true senior engineer? Take ownership, have autonomy, and be a force multiplier on your team. The Senior Engineer Mindset ebook can help 👉 swizec.com/senior-mindset. These are the shifts in mindset that unlocked my career.
Curious about Serverless and the modern backend? Check out Serverless Handbook, for frontend engineers 👉 ServerlessHandbook.dev
Want to Stop copy pasting D3 examples and create data visualizations of your own? Learn how to build scalable dataviz React components your whole team can understand with React for Data Visualization
Did someone amazing share this letter with you? Wonderful! You can sign up for my weekly letters for software engineers on their path to greatness, here: swizec.com/blog
By the way, just in case no one has told you it yet today: I love and appreciate you for who you are ❤️