Avoiding Ugly Hacks and Lazy Pull Requests: Five Keys to Boost your Speed and Quality in Software Teams

Improving software quality and velocity is no easy task. It depends on many things, especially when working with a team.

The following points are based on one part common software folk wisdom, one part my opinions, and one part the findings of a small questionnaire I made among my colleagues at Gofore.

Focus through goals and priorities

  • Do you know which task you should pick next?
  • Are you working towards one of your team’s specified goals?
  • Do you know what are the current priorities?

Clearly specified and prioritized stories and tasks give you focus. Focus drives motivation. Even if you receive an ad hoc task out of the blue, you should know its priority.

Uncertainty about what to do next creates confusion and leads to people doing the wrong things, or not doing anything at all. Skilled people might still find something useful to do, but don’t count on it in the long run.

Skilled people who talk to each other

  • Can you voice your opinion freely? Do you communicate fluently within the team?
  • Is the overall skill level in your team sufficient?
  • Do you have good team spirit?
  • Are mistakes allowed and do you learn from them?
  • If any one person is away, can you still continue development?

Good specs don’t matter if the actual people can’t code. Having experienced and skilled people in your team gives you more freedom and reduces the need for “babysitting”.

In practice there are always differences in skill level and experience. The only way to improve yourself is by doing and learning, so team support and good team spirit is essential for the newcomers or less experienced.

Good communication should extend to the product owner and client also. Feedback should work both ways and without delay.

Commitment to conventions and common workflow

  • Does your team require pull requests/code reviews?
  • Do you use linters to enforce code style?
  • Do you have team guidelines for version control and the task board?

People are different and prefer working in a specific manner. The team should come up with common practices that everyone agrees on. This can include things like how to write tickets, how to write commit messages, and which editor/plugins to use. Don’t make unnecessarily strict rules, though. Iterate and experiment to find the optimal way of working within the team.

The more people there are in a team, the more things you might have to specify, with more detail.

Confidence: trust in your code and automation

  • Have you automated as much as possible?
  • Do you have automated tests that test the right things?
  • Are your automated tests run automatically on every push/commit/PR?
  • If a test or a linter fails, does it block submission?
  • Are your pull requests high quality?

Confidence is the thing that separates good code from bad code. This means not only the confidence in your own abilities, but also the confidence that the overall system is working as specified at any given moment.

Confidence is tightly related to team practices but also the experience and personality of the individuals. You should always be confident in your own creations. Lack of confidence can be a result of inexperience of the current system, programming language or problem domain. It might also be that you’re just lazy. If you’re not feeling confident it is your responsibility as a programmer to increase this confidence by asking questions and learning actively.

How you approach code reviews/PRs displays this confidence. Is your mindset to submit something for the “judges” to see if it passes, or is the PR a way for you to display your awesome creation to others and receive the final stamp of approval? Submitting lazy PRs wastes everyone’s time. Don’t do it. Don’t transfer the responsibility of quality to the reviewer. Always review your changes thoroughly before submission.

Humans make mistakes, computers don’t (if programmed correctly). Automate everything you can. Use linters for every type of file you have. If you’re seeing the same typos or spelling errors again and again, create a custom static analyzer or a unit test to catch these. Avoid copy-paste errors with e.g. code generating tools. Notice your weak points and battle them with automation.

Implement meaningful, robust and effective tests and aim for zero regression. Whenever you encounter a bug, create a test for it so it doesn’t happen again.

Battling complexity: isolation and the proper amount of effort

  • Are changes done in isolation?
  • Are changes done in the simplest possible way without sacrificing quality?
  • Is your code modular enough?
  • Is your code readable and do you use naming conventions that everyone understands?
  • Is refactoring encouraged and is there time allocated to it?

As your codebase grows, so does your complexity and number of bugs. The overall increase in complexity can’t usually be reduced if new features are required, but the complexity of individual parts can be examined and minimized.

If you can achieve lower complexity or more isolation by refactoring, do it. Try to minimize the effect your change has on the other parts of the system.

Spend the proper amount of effort on a task, not too little or too much. What is the proper amount? You want to be just above the Comes Back And Haunts You (CBAHY) threshold (see figure below). CBAHY refers to the solutions you create that you know will fail at some point. If you must leave CBAHY code in, comment it accordingly. Don’t keep information only in your head, talk about it with your teammates or write it down.

If you go below the proper effort and CBAHY, you’re doing the absolute minimum: an ugly hack to make it work. If you go over the proper effort, you’re overengineering and optimizing prematurely. Added value vs. the time spent starts to decline rapidly. Remember that most of the time You Ain’t Gonna Need It (YAGNI) and even if you do in the future, you may need to refactor something when the time comes.

Conclusion

You can have the best specs, programmers, workflows, tests and architecture, but the overall software quality and the speed of the team is basically a commitment issue. It’s a team effort and everyone needs to be on board.

Implementing and taking into practice the things mentioned above will take some effort but it all comes down to one question: How do you want to spend your time? Firefighting the same old issues with substandard code or creating something elegant as a part of an unstoppable well-oiled machine?