Recently I embarked on a mission to read all the articles that I had bookmarked in the past and clear them out. The Code-first vs Product-first by Zach Lloyd is one of those articles. It was an engaging read, albeit one I only partially agreed with, given its perspective, from someone working in a tech giant. However, I believe most of the market is shaped by small and mid size companies, and considerations and problems of tech giants generally do not apply to small and mid sized companies. As a result, I decided to write about it.
Definitions
First, let’s see what does he mean by Code-first, and Product-first developers.
There are two kinds of programmers, generally speaking. There are programmers who care more about code, and there are programmers who care more about product. The former – I’ll call them “code-first” programmers – are obsessed with how code is architected, what tools, libraries and languages are used, how much test coverage there is – stuff like that.
Zach Lloyd – https://thezbook.com/code-first-vs-product-first
The product-first programmer cares about that stuff too, kind of, but only as a means to an end. For product-first programmers, the code is the scaffolding, the support, the steel beams in the building, but not the end product. The end product is, well, the product, not the code, and what matters to them is how well that product actually solves the underlying problem. Does the building stay upright? Do the elevators work? Is the A/C functioning? Do people like being there? Product-first programmers love building and launching and seeing users use what they’ve built. The product is the thing.
Zach Lloyd – https://thezbook.com/code-first-vs-product-first
Although I agree with his idea, IMO Life choices are not only black and white. Neither are developers. Let me explain more. One aspect with which we can categorize developers is their concern regarding code quality vs their willingness to ship fast or according to Zach code-first vs product first approach.
The journey
As juniors, we are more focused on syntax, language, algorithms, data structure, “how to”s. That’s when we’re learning to write code, and figuring out how to do things, how to work with tools, how to be a developer.
Then, as mid-level, we get involved with more abstract ideas, how to design, get to know “architecture”, and “infrastructure”. That’s when it’s starting to make more sense and the whole picture is getting clearer.
As seniors, after we got comfortable with engineering concepts, learned the tools and how to look at the big picture, we learn to work on “creating the best balance possible”. Based on the company culture, we try to understand when and to what extent to use the tools (including engineering concepts). No developer becomes a Senior, before understanding “how to make impact”. However, Seniors understand the importance of “Code Quality” – Zack also mentions that he cares a lot about quality later in this article. There is no seasoned developer in the market that has not been slowed down by “Technical Debt” in their career. What we call technical debt is all the low quality code that we have written or the code that we have not written, for many reasons, one of them being to ship fast and meet the deadlines.
Although I agree that all we learn as developers are tools in our toolbox to build a product that benefits our customers the most, I think what Zach calls Code-first developer, is only a reference to a period of time in every developer’s journey and not a category for developers. It’s all about the company culture. Company culture pushes developers to do things in the way they do it. In my opinion, all “Senior” developers are Product-first developers (Seniority not being dependent on the years of service only). And I guess, if there’s a senior developer that does not understand the importance of putting the customers first, he doesn’t deserve the title “senior”.
It all depends!
We all know the importance of Money. We all understand that we are part of a business and the business needs to make money by keeping its customers satisfied. The thing is, software is a living organism! and like other living organisms it rots over time if not taken care of. That’s why we all have seen or at least heard of products that make millions per year, but the code is nearly obsolete. Whatever the company makes, is spent on maintaining the monstrosity that is the product. That’s the point that everything starts to crumble. The point when the most important customer(s) of the product need a feature that we can’t develop reliably anymore and as a result customers start to churn. The point that product outgrows itself and fails with performance issues. The point that each release causes more bugs because of lack of quality-assurance measures. That’s the point that the piles and piles of spaghetti code (read low quality, high debt code) has rotten and turned into a swamp!
It all depends! It – the balance between quality and quantity of features – depends on the product, resources, deadlines, and most importantly the company culture. If you are in a stage that you do not even know what is the product, then yes, of course, put some pieces of code together and see if the fish bites! The problem is that this becomes a mindset, this becomes the culture of the company! It becomes an excuse for developers in the team to not care, to come up with some hacky solution, to put some low quality code together to mark the next task finished, although the company is 5, 10, 20 years old! That’s why it’s extremely important who are the first hires of the startup / company. So they can redirect the company toward quality-assurance (not only tests but on every step of the way) as soon as state of minimum stability is achieved.
Unfortunately the fact that “Technical Debt and low quality code is the main reason the company is bleeding money” is something stakeholders do not understand, and it is quite hard to prove that, “hey, you have spent for example 15 million euros on this product over 5 years but what you got in return is only worth 1.5 million! And the reason for that is the low quality of your code base!” First of all, how are you going to measure that? – it’s possible of course, by sitting down and imagining if it was a fresh product with no technical debt how long would it take to build that feature but overall it’s not easy to calculate it for a company with tens or hundreds of developers over multiple years. I guess the other main reason is that admitting it, means not-appreciating all the good work our x-coworkers, current coworkers and even ourselves have put into building this product that is generating millions and somehow it feels dismissive and incriminating! It feels like pointing fingers, although it’s just stating the current state. Specially when we understand why they made the decisions that they made which is often pressure from the business to deliver faster and faster. Low time to market and shipping fast is vital for a company but also is code quality. It’s all about the balance.
Over-engineering vs Technical Debt
Let’s read another paragraph from that article:
Conversely, when I see programmers not launching features quickly, the issue is often overengineering. Or when engineers do launch quickly but the quality is bad, then the issue is usually under-engineering or sloppy code.
Zach Lloyd – https://thezbook.com/code-first-vs-product-first
Contrary to Zach’s point of view, when I see programmers not launching features quickly, in small and mid size companies, startup or not, the issue often boils down to one of these 3:
- Technical Debt
- Procedures
- Communication.
Over-engineering is not the primary problem. I only concentrate on the technical debt topic as it’s more aligned with this article. I also need to mention that, firstly, according to my experience, experienced developers know about “YAGNI” rule, and they do not try to build something imaginary – of course you need to have someone that prioritizes the product and has enough supervision to point everyone at the right priorities. Secondly, most of the time what people call over-engineering is what they don’t understand. It’s a way of dismissing something they don’t understand, and at the same time keep their ego intact.
Think about it in this way: If someone over-engineers a feature probably he will be spending 5 days or a week extra to think things threw (considering, in most agile teams Sprints are not bigger than 2 weeks). That is in the end for a main feature and probably will bring a lot of freedom in the future. As I said before, it all depends, I understand that if you are an early stage startup you can’t even afford spending 5 days, and I understand it’s a wrong thing to do and should not be like that. Now, if someone wants to change an existing low quality feature in a product, almost all the time, time that he spends is to apply the change without breaking the existing code! Can you see the lesser of 2 evils clearly now? – The answer is although both are bad, Technical Debt hurts the product more than over-engineering.
In the end, It all depends! On one hand, it doesn’t make sense to try to build a “perfect product” imagining things that we might need 5 years later – You are not gonna need it. On the other hand, I completely disagree with the “we’re a startup, and that’s why we don’t care about code quality” argument, which translates to highly coupled code, no engineering, no architecture, no tests, etc. Those things that people dismiss completely, will cost the company millions.
I should mention, in some industries you can not do that at all. I mean shipping high quantity of features with low quality in some industries is not possible at all or at least it’s unethical e.g if you are building a product that can be a life threat to someone, health care and lab software, software used in spaceships and airplanes, self-driving cars, core banking of most Fintech products, etc. In these products, it’s important to be more cautious, and ship with higher level of reliability, you shouldn’t ignore quality at all. Otherwise, your code might cause irreversible damages to someone’s life. As a result, if you are hiring someone from these industries for an early stage startup, – well – you should not! That person has been living the “quality-first” lifestyle, and changing habits does not come naturally.
That being said, I agree that over-engineering is a real thing in software industry. There are engineers out there that try to apply principals and approaches of companies on the scale of Google to small startups. That’s one of the main categories of over-engineering that I’ve seen a lot e.g when Microservices became a thing, everyone wanted to do microservices architecture without considering any other aspect of their product.
Great developers
Let’s continue with the article. He continues to say:
There’s no zero sum game here: you should strive for good code, produced quickly, leading to great product. This is what great programmers produce.
Zach lloyd – https://thezbook.com/code-first-vs-product-first
This is what I completely agree with. That’s how it should be. It’s all about “the balance”. Great developers – if company culture allows it – build features / products that are most desired by customers, implemented with good code, consider the current and near future requirements, and ship it fast and reliably! In my opinion, a great developer, is the developer that:
- Has Great knowledge of software engineering concepts (in depth and width)
- Understands the product domain
- Understands the priorities of the company (which are or at least should be priorities that benefit the customers the most)
- Understands the existing code, tools, and procedures of the company
- Knows how to clearly communicate – on daily topics, on technical or non-technical discussions, written or verbal
- Cares! (the most important one) Cares about the customer, the company, coworkers, the code and the software as a whole
Conclusion
The solution is finding the best balance that works for the product you are working on. Don’t be the code-first developer that writes code that does not create much value. Don’t be the product-first developer that writes hacky code and makes others’ life harder. Write code with low coupling, and high cohesion. Pay attention to separation of concerns. Consider change management and quality assurance to the extent possible. At least in this way, as company grows you can replace the parts that are causing problems. And finally ship as fast as possible. Shipping fast means unblocking other parts of the company so they can do their part.