From 5 employees to 50 — How to keep software maintainable

Kai Rollmann
neXenio
7 min readJul 24, 2017

--

In May 2016, I started working at neXenio. As the first frontend developer for our main product, I had the honor to set up an initial React web app.

Now it’s about two years later, April 2018. We’re 50 people in total. In one product alone we have 5 frontend developers working on 6 React apps in one mono repository. Over the last year, we have been hiring engineers, replaced tools and have switched teams around. We created tests and threw them away. We moved testing into a full-time team. We organized various talks, sync events, defined processes and replaced them with better processes. We wrote and deleted a lot of code, pair-programmed, reviewed. Yet one fact remains: our code base is growing.

With a growing amount of code — as is natural — we’re constantly weighing building things quickly versus building things the right way. Luckily, at neXenio, time in the long-term is well cared for. So even though we’re sometimes on the edge of meeting a deadline here and there, in general, there is time to build things the right way, to build software sustainably. Also, our products revolve around secure collaboration. So by that nature, they don’t permit a fast-paced and possibly error-prone implementation.

Here are some of the lessons we learned on the way. These lessons are written in the imperative to shake you up a little. Get ready! Of course, the following might also be biased with a dash of frontend-perspective. So be sure to pull out your “well-let’s-see-what-that-JavaScript-guy-has-to-say”-glasses and start with:

1. Write handsome code

At all times during a project, you need to be able to onboard new engineers. They will want to feel empowered to not only add, but also to change existing code. Everybody loves working on a solid code base. So ideally, when new engineers in the team read the existing code they should be able to understand it piece by piece, domain by domain. And even though they might have different ideas about an implementation, they should be able to appreciate the way the code has been written so far.

What we learned is really plain: Don’t write ugly code. At least try very hard not to, because that will make all the difference. Ugly code leads to misunderstandings, knowledge-islands, frustration, bugs, and eventually, re-writes. Of course, as a code base gets larger, we can never avoid issues like these completely, but definitely to a large degree. In the end, code is always the medium of how you communicate with others. So don’t let yourself down and don’t let your peers down either. Make an effort. We can recommend: Write easy to understand, easy to throw away, good looking code.

2. Care about the code around you

It’s possible to do a refactoring sprint. It’s also possible to minimize the technical debt for a few weeks. In our experience though, that quickly leads to too many changes which are hard to estimate, hard to coordinate, hard to integrate and also very demanding for the few people who are tasked with such important refactorings. What worked way better was to refactor as we went. The perfect workflow looked like that:

I’m working on a rather small task. Until now, the change set was quite tiny, but I suddenly realize that I need to refactor 2–3 other files because if I do, my small change fits better into the overall architecture. I could of course postpone that refactoring for now. But I don’t. After taking 2–3 hours more than I planned to, the change set is a little larger, but it’s still reviewable and I’m happy with the result. My reviewers are happy as well, they even thank me for taking care of things along the side. Other tasks had to wait. But that’s fine.

The additional hours were well spent and the code quality remains strong. Nowadays, we have many engineers working in this way and we can highly recommend you trying this strategy out, too.

3. Yes — you *can* split that

Penelope Persona wants to manage her account portfolio. She wants to create an invoice and assign it to her team members. When she’s done, she wants to see a summary of what she just did.

That’s great for Penelope, empowering her with these fancy features would certainly make her and your product owner very happy. And it’s just a few sentences, right? Also, it’s a sweet, single workflow. That suggests to do all of the changes in one go, right? Right? Of course not. Granted, this particular constructed example story is obviously too large. A ladybug on the outside of your window could smell that invoice creation, invoice assigning, and seeing a summary should be split up into three separate tasks, stories, or which ever entity of todo item you’re working with.

But even if you simply took the process of invoice assignment — you would need to specify: What’s supposed to happen if Penelope assigns an invoice to a single team member only, versus what happens when she assigns multiple people? Is a multi-assignment something she needs to do right away? Or would implementing a single-person-assignment be atomic and still complicated enough to create a well-sized change for a first pull request?

We’ve learned: when in doubt, split the task. It’s again a very easy thing to know you should split, but as beginners we often refrain from splitting, because we think it takes more time than doing it all in one go, or because it’s a hassle to extract both tasks because communication with more stakeholders is necessary, or maybe the issue tracking software gets in the way — reasons like that. Hold up against these mental barriers! Divide and conquer. Take the time. Split tasks, because you can. It makes everyone’s lives easier. And then:

4. Be a little strict with reviews

Now someone has made a change. You might be under time pressure to get the feature in. But even then: Don’t accept a pull request when the changes are just barely fine. At all times, code should speak for itself. When the diff doesn’t meet the best reviewer’s quality standards, you’re likely not done yet. We’ve learned that you can’t avoid getting inconsistencies here and there as the code base grows, but you can steer the right way during a review. Accepting changes too quickly communicates that it’s fine to be a little sloppy. That’s fine when you’re prototyping, or building an MVP that you throw away half a year later. But for everything beyond that time frame, sloppy is the enemy. So be a little strict. If you want to avoid too many nitpicky comments, adjust your linting tools. Most of the time, that’s easier than you think. Now talking about being strict, it’s also important to:

5. Give friendly reviews

Here are a couple of simple things we keep in mind.

  • When you comment, be very concise. Stick to the point.
  • Give concrete suggestions. When you don’t like something, always suggest a very concrete, better way.
  • Try to avoid second questions and another comment-round.
  • When you don’t understand something, be curious, ask. Maybe the code isn’t clear enough, maybe there is a code comment required, maybe the namings aren’t good enough yet.

But all of this can be phrased in a friendly way. After all, you’re reviewing the work someone has likely put a great deal of effort in. So be direct, but be friendly.

6. Give proper reviews

In general, when you pair-program a lot, you have to spend less time reviewing. Which ever way you lean towards should depend on the team’s preference. The less you pair-program, the more you’re reviewing.

But when you review, take the time to try to understand everything, yes, everything you’re reviewing. Not only does it help you to understand how someone else thinks or approaches solutions — a thorough review of the code of someone, who has a little more experience, makes you learn about different programming concepts. Review on all abstraction levels. Think about the idea behind the implementation, its extensibility, but also think about formatting and naming. Either of the two alone aren’t good enough if you want to maintain a sustainable code base in the long run. Train yourself actively to take care of the level of abstraction that you tend to forget.

7. Introduce change gradually

Let’s say there is way “banana style” do do things. Marry wants to introduce the newer, better way – “cherry style”. Should she have to refactor all places where banana style has been used so far? At some point, when the code base is large enough, it would take Marry a very long time to refactor all “old” places using banana style. We found that it’s enough, if you inform every person involved with the code base that cherry style is the definite way to do things from now on and that everyone should take care of changing the banana style code to cherry style, whenever they touch code that still uses banana style.

So Marry submits a new feature that uses cherry style. She talks to everyone and shows how to work with that new style. Future uses of banana style won’t be approved anymore from now on.

If communication works, we found that this is the better way to go forward compared to postponing change for the fear of having to refactor all places. Of course, it’s important to take the time to discuss, whether cherry style is really superior to banana style. But as soon as that is decided, we can recommend: embrace change and communicate it well.

8. Enjoy time with your peers

As you found out by now, we’re caring about how we build. But we also care about who we build with. Appreciate your co-workers. Help them out. It’s almost impossible to grow sustainable software without growing a healthy and happy team as well. Spend time to find out about individual motivations. Figure out how to get your peers what they need. Make them reach their goals. All of these things should be obvious if you’re in it for the longer term, but that’s what’s often forgotten over product deadlines or feature requests.

Conclusion

In short: You can build software sustainably if you make an effort. Even the process can be pleasant for all those involved.

We hope some of these lessons we learned will set you in the right mind, one way or another. If you have any feedback, comment or drop us a message.

--

--

Kai Rollmann
neXenio
Writer for

Applied enthusiasm. Relentless vision & technology. Gliding through life with a wing.