I started a greenfield project this week. I knew it was coming after one of our product managers told me about it during lunch a couple of weeks ago. To be honest with you, I was terrified. I’ve been at madewithlove for a little over 4 years now, working exclusively on existing (legacy) projects for customers. Before that, I worked for several years as an employee and freelancer on existing projects. Barring small internal projects like Invox and some libraries, I can’t even remember when I last built a serious product from scratch.
In the last couple weeks I mentally revisited all the legacy projects I’ve worked on. How am I going to avoid walking into the same traps? What if I end up making mistakes that grind the project to a halt before I realize what has happened? How can I leverage what I’ve learned from all these past projects to build something “the right way”? It was a lot to think about, but I had a couple of weeks to sleep on the problem and managed to start the project in a confident way.
Below is a summary of the key ideas that managed to calm me down and will hopefully make the project a success.
Ship early, ship often
I knew that the first work I would do on the project was to build a functioning CI/CD pipeline that runs tests, enforces the highest possible code quality, and can deploy to a working “production” environment quickly and frequently. This one was a no-brainer for me. I’ve seen so many projects that couldn’t ship reliably that I wanted to get this out of the way first. Luckily, we have plenty of internal projects with a similar setup, so this would be easy to do. Since we will be using the Laravel framework, I plan to configure php-cs-fixer to enforce and fix code style, set up Larastan, a phpstan based static code analyzer, at the highest level of strictness, and run feature and unit tests. All of these will run through Github Actions to validate pull requests. Continuous deployment after merging to the main branch will be handled by Forge.
Stick to the absolute minimum
The thing I was worried about most for myself is building too much. I will continuously force myself to remove anything from a pull request (PR) that’s not needed to solve the current problem we’re working on. I want to delay every decision right up to the point where it’s necessary to take it. If there is a simple solution, build that first. Complexity can be added gradually while refactoring the current solution to include the new scenario. If anything, I don’t expect to see code living very long in this project, as it will be moved around and changed frequently. While this might feel counterproductive, it’s not a problem at all. The effort put into refactoring a simple solution is peanuts compared to wrapping your head around overly complex abstractions 3 months down the road.
Feedback, feedback, feedback!
I have a really strong team around me, so I want to learn as much as possible from them. I asked my colleague to be brutally honest and very thorough on my first PR, just to make sure we quickly understand each other’s code style and what conventions we’re going to use in this project. Getting that out of the way early will smooth the path going forward and immediately builds a trusting relationship where honesty is not only appreciated but also expected. Much to my delight, she delivered like a champ and challenged many of the choices I made. We’re building this project for a customer. Later on, we will help them hire their own engineers so they can take over the project. Maintaining a culture of honest and frequent feedback will be crucial to set them up for success.
No shortcuts on quality
Building good software takes time. Sometimes, it takes too much time and we want to take a shortcut somewhere. If there’s one thing I’ve learned over the years, it is to never take a shortcut on quality, but always on the scope. If you need a solution tomorrow, come up with a simpler solution and deliver it to the best of your abilities. Delivering half-assed work in a rushed way is a recipe for disaster. If you do it once, what’s going to stop you from doing it again? What’s going to stop the other engineers on the project from doing it? It’s like an avalanche of poor decisions burying you in technical debt. Not going to happen on my watch.
What’s the trade-off?
With every non-trivial decision, I want to understand the trade-off. What are we giving up when we choose to take a path? What will it cost us if the decision turns out to be wrong? How easy will it be to change our minds later on? And probably most important: what would it take to delay the decision? If it turns out the trade-off is not clear and I need to make a decision, I will keep digging and involve the team. Additionally, important decisions and their trade-offs will be documented in a DECISIONS.md file in the repository because this information is easily lost over time.
Collaboration over speed
In greenfield projects, it’s easy to get carried away when you’re cranking out features. I want to make sure that collaboration remains an important value in the team to ensure knowledge sharing and high-quality results. There are always situations where the thing you’re building is trivial enough to do it on your own, but whenever I’m on the fence about something, I want to include a second opinion. Whenever I start on a new big chunk, I better involve someone else to double-check my assumptions and to challenge my proposed solution.
These are my guiding principles for now and, even after we hand the project off to an external team, I hope they will continue to be used. In greenfield projects, we not only have the chance to build high-quality software, but we get the opportunity to shape the culture within the team building that software. What I’ve seen plenty of times in the past is that the latter turns out to be more important than the former.
Other interesting reads
- Public speaking at madewithlove
- Workshops on remote
- Better code reviews
- Our retreats
- Read more about the work we did for Gearjot