In a growing project, developers should prioritize delivering business value over striving for perfection in their coding practices. Tools and technologies are merely means to achieve end goals, not the goals themselves. It’s essential to question the necessity and timing of implementing features or tools based on their immediate value to the project. Developers should also focus on understanding the business aspects of the project, anticipate risks, and provide scalable solutions without getting bogged down by the desire to use perfect code or architecture from the start. Collecting feedback and adapting based on it is crucial, as is maintaining a mindset geared towards effective, value-driven outcomes rather than perfect solutions.
Mastering a lot of technologies and knowing how to build complex, high-loaded services turns out to be not enough when you're a developer in a startup or growing project. In my career, I’ve been involved in many growing projects and created two startups from scratch. In this article, I'll share my experiences about what to focus on during development and why perfectionism spoils even the best ideas.
Tools Are a Means, Not an End
For every developer, launching a project alone is a solid challenge. It's very natural to feel that you need to do everything perfectly. It took me a while to realize that the desire for perfectionism is most often the reflection of fear that colleagues will judge me for an extra 'print' or not using a pattern or tool; and here, it goes: the production server will collapse, clients will complain, I will be fired, and the world will come to an end.
Any tool, pattern, or programming language is just a tool, not a goal. Question more often: Why do I need this now? What will it provide? Which metrics will it improve? For example: why configure a linter now? Why customise CI/CD now? If you're doing a deployment 10 times a day, you probably need it. If you deploy a release once a week or month, most likely you don't. If CI/CD customization will take a lot of time, but won't speed up development or bring value to the project and customers, should it be implemented now?
In a pet project, it makes sense to try something new: endlessly improving the structure of the repository and code, experimenting with patterns, etcetera. In this case, the tools we implement are the goal. The main goal of a production project is to deliver value to the clients. Clients will never know that we use double quotes instead of single quotes, and singletons, and there is no hardcode.
Refactoring is necessary only when it will increase development speed and performance, reduce bugs, or unblock the backlog.
The commitment to quality should pursue the goals of the product, not your desire for perfectionism. So, it's important to remember: a developer in a growing project is never a perfectionist.
Business Value Comes First
For a developer in a growing project, it's essential to understand the business value. When you're used to being a regular developer who codes only according to ready-made specifications, it can be challenging at first.
When the product is just being born, the value to users is not yet proven, but the value to be proven exists in the stakeholder's mind. At this stage, you can make the mistake of overloading the codebase with unnecessary logic. For example, you need to write an order handler. You create one table with orders in the database and a second table with order types, although there is just one type yet.
Let's say you do this because the stakeholder insists that someday this logic might be needed. In reality, it may never be needed. Don't spawn unnecessary entities if there is no value in them now, and more importantly, don't waste business time and money on that.
A reasonable question might be asked: "Am I going to argue with a stakeholder?" Well, sometimes you will. Stakeholders expect detailed analysis. Specifics of growing projects are most often a lack of resources, so developers must have analytical skills. You need to constantly validate the value of features for the product, as its viability literally depends on it.
If you spread yourself thin, the business will run out of resources and you'll archive the repository.
Ask a lot of questions: "Why implement this feature now? Should we solve this problem now? Does this problem even exist?" It's exactly the same as described above with technologies. Being able to ask the right questions reveals your professionalism. You need to only spend your time and business resources on things that truly bring value to your customers.
Hackathons are a great example showing how understanding the business value influences the result. Within a limited time, a non-ideal but workable solution to a clearly defined problem must be presented. When developers are inspired by the project and clearly understand why they do it, the result comes out well even in 2 days.
The Plan Depends on Risks
Imagine a strategy game: you have a lumberjack and a recruit. The goal is to create a warrior. First, the lumberjack must collect wood and build barracks, where the recruit can learn military training. To harvest the wood, the lumberjack needs to reach the forest through an unexplored part of the map. Judging from the map, the forest can be reached in one game day, the woodcutting will take about half a day, and building the barracks will take a week. So the barracks will appear in about ten days.
The lumberjack takes almost a day to get to the forest, but suddenly the river blocks the path. The goal changes: we have to build a dam, a bridge, or a boat to get to the other side, or maybe it is better to look for forests elsewhere. Premature evaluation leads to a breakdown in strategy. If the scout had explored an undiscovered part of the map first, this risk could’ve been avoided.
An experienced developer recognizes risks that are not obvious to the stakeholder: integrations with third-party services, the complexity of extending the code base, and so forth. It is your responsibility to evaluate the risks and warn about them. Most often stakeholders are unaware of these risks, but they affect the evaluation, which is important to them.
An example task: integrating your service with a payment service. First of all, set up the payment service, get access, and investigate where things can go wrong. Before integrating, understand how to integrate. It's better to spend a day on the research than to find out after two or three weeks of development that the feature can't be finished on time or the integration has failed because the payment service has changed the terms or disabled support for the needed feature.
After working out the risks, you need to plan the work and provide a time estimation for the task. This is the framework I use:
Write scenarios or visualize them on board: e.g., the user clicks a button, and the document is downloaded. Choose approaches that you understand.
Analyze how the script could work from a more technical standpoint. The more options, the better. I evaluate the options and choose a potentially scalable solution with minimized risks that would solve the problem most quickly.
Break the scenarios down into logical parts that need to be coded.
Estimate each part in days, and then multiply by the 1.11 coefficient. This is my personal magic coefficient, which is my birthday on October 11. This is, of course, a joke (or not). My advice is to add a couple of extra days or even weeks to the estimation, depending on the project scope. While we try to foresee as many risks as possible, some cannot be foreseen. It's best to get things done sooner than not succeed.
Don't be afraid to give a larger estimate: when a stakeholder asks, "Can't you do it faster?" don't just answer "No", but justify why. Tell about the risks, demonstrate scenarios, and give examples. The stakeholder needs to understand that you have analyzed the problem and not just randomly assessed it.
Important aspect: your state of mind is also a risk. Plan your vacations, and keep an eye on your mental health to stay motivated and not burn out: it's your responsibility.
MVP Is Not a Spacecraft
The question "How to create an MVP?" has bothered me my entire career. Sounds simple - Minimum viable product.
Wikipedia definition:
A minimum viable product (MVP) is a version of a product with just enough features to be usable by early customers who can then provide feedback for future product development.
I have often observed that when you need to build an MVP, sometimes it ends up more like constructing a spacecraft that takes a ridiculously big amount of time. The main goal at the MVP stage is to get quick feedback from the client and, based on this feedback, agree with the stakeholder whether we 'go straight' or 'take a right turn.' The best way to gather feedback is metrics. It's great if they succeed without them, but if it doesn't, at least you'll know why.
I'll tell you about my first MVP. I found many tools and frameworks: UML, Design Patterns, Roadmap, Story Points, System Requirement Specification, ADR, UI tests, and so on. I decided to use all of these because these frameworks are used inside large companies, and I heard about them at conferences, lectures, and YouTube.
The purpose of the service was to store data about test runs. I put together a roadmap for a year, drew a detailed architecture in UML, spent a long time choosing a framework for the backend, set up a system for testing and logs in Sentry, and calculated the load on many users instead of the expected 10-15. I wanted to make the perfect project.
The first version took 6 months to complete. You could look at all the launches and graphs and download reports, but there was a problem with data collection. Two or three times a week a broken report appeared, which made the service impossible to use, but I stubbornly followed the plan.
Over the next few years, I had many different projects and tried to launch my startup. I learned about marketing, sales, and client pain. The experience changed my mindset and allowed me to develop the approaches I share in this article. I'll describe a recent task to demonstrate how they worked practically.
I needed to speed up the API method, which annoyed users with its slowness. The plan was to move it to a separate service from the monolith, where there were difficulties due to a lot of integrations with internal services and data structures. This project was experimental - no one knew if acceleration was possible.
Of course, I could go ahead and suggest rewriting everything and making it perfect. I started by researching the monolith and internal services and investigated the risks of integrations. Then I created a strategy using a simple diagram in Miro, broke everything down into iterations, and only then started working.
From time to time, there were problems with integrations about which the stakeholder was the first to know. First of all, we solved them. Yes, there was still technical debt in the project: linters, incomplete tests, old schemas in the database - but the clients' problem was solved.
At each iteration, I collected metrics on how the API method was performing:
Slow and with errors, without release.
2x faster and with errors, without release.
5x, 1% errors from all requests.
6x faster, without errors.
All iterations hit the target, and on the 4th try, we hit 100%. It would take 10 iterations to rewrite everything from scratch, but even in less time, we got a scalable service that solved the problem. The only question is the approach.
Codex of a Developer in a Growing Project
Let go of perfectionism. While the world is full of technologies that solve problems, you don't need to know everything to make projects useful to people.
Use ready-made solutions where possible.
Business value comes first. Users don't come for a product, they come for a solution to their problem.
Evaluate risks from the start and communicate them to the stakeholders in a clear manner.
Make short-term plans. If the task has been on the backlog for two years, most likely, users don’t need it.
Collect feedback and metrics in every possible way. Metrics are a reliable way to find growth points.
Scalable solutions can be achieved even when the "right" engineering patterns aren't used at the start.