How to keep the product release process tight when growing fast

Ennio Masi
YNAP Tech
Published in
8 min readFeb 7, 2020
Photo by Nikita Bren on Unsplash

The iOS Team at YOOX NET-A-PORTER GROUP doubled in size in 2020.

Growing our Team like this allows us to do more and be even more ambitious than before, but this rapid growth has created challenges of its own, in particular when it comes to developing, merging and delivering features.

So, over the course of 2019 we spent time thinking about how our engineers could best cooperate and release code smoothly, with a focus on fostering a culture of continuous improvement and continuous knowledge sharing across the Team.

Continuous Improvement

As part of a Product Team, our main job is to deliver features that our colleagues across the business want and need. Sometimes that makes it difficult to schedule in time to polish the existing architecture, especially because it can be difficult to measure the business value of the changes.

That is why it is really important that the Developer team is accountable for the continuous improvement of the code base — this enables team to be more productive in the future.

Taking this view, the Opportunistic Refactoring concept becomes a key tenet of our day-to-day. Martin Fowler, who coined the term, describes it as follows:

[..] What this means is that at any time someone sees some code that isn’t as clear as it should be, they should take the opportunity to fix it right there and then — or at least within a few minutes. This opportunistic refactoring is referred to by Uncle Bob as following the boy-scout rule — always leave the code behind in a better state than you found it. If everyone on the team is doing this, they make small regular contributions to codebase health every day.

As a team we agreed on a basic foundation principle: always try to improve the code you are working on, also known as the boy scout rule.

Examples of Opportunistic Refactoring are:

  • Remove outdated TODOs from the codebase you are working on
  • Fix warnings from the codebase you are working on
  • Fix Auto Layout constraints from the UI you are working on
  • Remove the usage of self in the codebase wherever possible
  • Add type annotations where necessary, to reduce the time taken to infer types
  • Add unit tests to untested code
  • Add snapshot tests to untested UIs

To refactor what you are working on is repeated frequently because refactoring is always welcome when it’s related to the feature/issue/piece of code you are working on. And as a general rule, refactoring is always welcome provided we keep the product release’s size under control.

This is because it’s quite common that, especially working on legacy code, a local refactoring quickly becomes larger than expected and it can make reviews by your colleagues more difficult.

It’s important to highlight that without a good test coverage the you cannot conduct opportunistic refactoring with proper confidence of not shipping code with regression. Please treat unit tests code as first class citizens 🙂

Continuous Sharing

Working on a rapidly evolving large codebase, being a good boy scout sometimes is not enough, or sometimes it’s not possible at all because it would imply too many changes that would slow down the current development and the next release.

So when one of us notices any large piece of code to be refactored or removed we track it on a confluence page to be discussed in our tech meeting. In this way we get two benefits:

  • The entire team is aware of what’s going on in the project;
  • The entire team is responsible for prioritising our next tech tickets to work on;

It is also important to highlight that when your team grows quickly, it can be near impossible for the entire team review every Product Release (in our team, we sometimes have ~30 PRs open in parallel), so we need to help the team understand and feel confident in what will be merged.

However, at the end of the day our main tool are Pull Requests, so how we raise them and review the code can change the team’s approach to its work. That’s why we decided to create a more sophisticated flow using Github instead of relying exclusively on JIRA.

Pull Requests structure

I am a strong believer that a team will work better if you can help its members individuals to:

  • To be more emphatic;
  • To understand the value of self-assessment;

This should happen when we are ready to share the code with our colleagues, usually before raising our Pull Requests. That’s the reason why we structured them like this:

Example of PR structure
  • Product Release Title: The title is the entry point for any review, it must make sense for the colleagues, so our format is like [Task|Story|Bug]/ticket_no: short title; keep in mind that’s also useful when you generate the release note;
  • Ticket reference: It’s the anchor to the ticketing platform, useful for colleagues to get more context if needed;
  • Description: Explaining why you have taken decisions is more valuable than describing what you have done. The team should be able to understand the decisions made when reading the code. Sometimes a how section of the description is useful too;
  • Regression Areas: Make it clear to the QAs and any developers affected by the Product Release that they are affected and need to pay attention. It is not always immediately obvious by reading the code and sometimes people just do not have time to read code that’s not immediately relevant to them; we have effectively noticed that it’s useful to give context for both the review and testing phases because we cannot imagine that everyone has a full knowledge of the whole project;
  • Milestone: Assign your Product Release to a milestone that is related to one of the future releases, in this way generating the release note would be super quick!
  • Checklist: This is the self-assessment phase. In past few years I’ve started to review my Product Releases before raising the checklist. And before I share the checklist, I take a step back and and read it as if it’s a Product Release from someone else. It is probably one of the most valuable exercises to facilitate a seamless review process;
  • Labels: Labels help us tell our colleagues the current status of the Product Release. In our team, we have In Progress, Review Needed, Ready for Testing, In Test, Work Needed, Testing Approved; The following chart shows the lifecycle of a Product Release. For a Product Release to be approved and move from Review Needed to Ready For Testing must receive at least three approvals;
Pull Requests flow

Once the Product Release is raised and it’s in Review Needed state, the possible flows are:

  1. If the Product Release gets at least three successful reviews, it goes to Ready for Testing;
  2. If there are comments to be addressed, it goes to In Progress;
  3. Once the Product Release is moved to In Test, then it can go back to Work Needed if there are regressions or requirements not met, or it can go to Testing Approved which means it will be merged;

Code review principles

For us the primary purpose of a code review is to assess the YNAP iOS code health and to make sure it improves over time. This is tricky because any evolving code tends to incrementally decrease in quality, that’s a fact.

So the goal of any contributor in our team is to feel comfortable contributing to the codebase, delivering features, refactoring code, etc., keeping in mind the team guidelines and trying to follow the project general architecture.

Each reviewer, on the other side, has responsibility for the reviewed code too and they should only approve a Product Release when it’s in a state which improves the codebase, even if it’s not perfect. This doesn’t mean that any Product Release must be quickly approved and as a general rule the reviewer shouldn’t be afraid to request changes and the contributors shouldn’t take any denial as personal judgment.

Criticism is almost never personal in a professional software engineering environment — it’s usually just part of the process of making a better product”. Fitzpatrick, Collins-Sussman: Debugging Teams, page 16

All the comments on Product Releases should not be driven by personal preferences, rather raised with the common goal of building a better codebase (in terms of both maintainability and testability).

In terms of coding polish and general Product Release health checks, we make sure that the code guidelines are followed making automatic checks on the Product Release via Danger:

General approach reviewing a PR

  • Be humble!
  • Be open!
  • Never judge people personally, always refer to code and solutions (talk about the code, not the contributor);
  • Respect and trust the contributor;
  • Comments should follow best practices, not personal style preferences;
  • Don’t leave open comments, suggest solutions instead;
  • Don’t put pressure on the colleagues! From the author perspective, it’s not fair to ask for any urgent review to the colleagues, a request like “Can you please approve my PR?” should be replaced by “Can you please review my PR?”;
  • Celebrate 🎉! If you see some code, a solution, an approach that you really like, let the contributor know! That always builds the team’s morale 🤗

Product Release conflicts

If for any reason there is a code conflict, the best way to deal with it is for the contributor and the reviewer to have a face to face conversation. If it doesn't help for any reason, we arrange a 30 minutes meeting with the whole team to talk about it.

Conclusion

Over the course of the past year we have really improved how we raise and manage our Product Releases and have found a way that is truly effective for our team. I hope some of the suggestions can help other teams but I’m 100% sure that in the future, our set of guidelines andgeneral rules around the process will change entirely. It’s definitely an evolutionary process that will never be perfect and one that helps us exercise our adaptability!

However, one thing is certain, whatever approach you take — you need to have strong shared values underpinning your team’s approach. For us, these are empathy, respect and humility — I think they’d probably work pretty well in any organisation 😉

Feel free to contact me on Twitter for any comment. I’d love to hear any kind of feedback! ✌🏼 And I hope that this article can help you and your teams!

Thanks for reading! 👽

--

--