Developing a Culture of Quality Code

This post is the companion piece to my presentation at Midwest PHP 2020. It contains helpful links and reading selections.


Why Do We Need To Maintain the Quality of Our Code

As engineers, we spend a lot of time reading code so we can add new features and fix bugs. Keeping quality in mind makes it easier for us to do this.

I used to work for a company that sold an application where for the first five years of its existence speed of new features delivered to clients was the most important metric (this happens a lot). This caused code to be added quickly by duplicating code from other parts of the application and not fulling testing changes. As we matured the product, this prioritization of quickly releasing new features caused a high number of defects that made our lives as developers harder and caused our clients to be upset. By focusing on quality we were able to reduce the number of bug reports and still deliver new features to our clients quickly.

What is Quality Code?

The concept of “quality code” is fuzzy and a little hard to define. You can search Google and find lots of articles that explain what metrics you should use and what their definition is. For this article, we’ll define quality code using a modified version of CISQ’s quality model. We have them in a different order (to show their importance) and we added a new first element.

1. Purpose

The most important quality indication is that a piece of code has a purpose and that it’s fulfilling the needs of your customers. Without these two criteria being fulfilled, there isn’t any reason for that code to exist.

One of my ex-workers works with another programmer who would get an idea for a feature and stop work on everything else for weeks while they wrote the feature without consulting anyone. They would then deploy the feature to find it wasn’t used because it didn’t fulfill a need for their customers. This code now has to be maintained and makes it harder for them to develop new features and improve other code.

2. Maintainability

The second most important quality indicator is if the code is maintainable. Keeping your code so it’s easy to change will allow you to remain nimble and quickly release new features to your customers.

3. Reliability

The reliability of your code is necessary to keep your application running with few bugs and little downtime. Having software that isn’t reliable will make it hard to attract and retain customers.

4. Efficiency

Efficiency is another characteristic that is important to attract and retain customers. Your application needs to maintain high performance as it’s been shown that a “1-second delay in page response can result in a 7% reduction in conversions”.

5. Security

Depending on your industry, the security characteristic can be a legal requirement or nicety but either way, you want to make sure your customers’ data is secure and not accessible to malicious actors. Think of how often software companies get bad press for losing their customers’ information. Do you want to be in that group?

6. Size

The size of your code can affect the maintainability of it because large codebases make it harder to add new features.

How Do We Alter Culture?

Altering a culture at an organization is hard. It’s not something you can come in on a Monday morning and say “we’re not doing blah”. It’s something that can only be done through hard work and discipline.

This change can either be team-driven where the team as a whole work to a common goal or be engineer-driven where individual engineers work to improve their code. Team driven is a little harder because you’re asking others to change their workflow and change is hard for humans. Engineer driven is easier because you can make small changes and learn what to do to make your own life easier.

The Engineer Driven Options

I’m guessing most of you are not in the C-suite so let’s start with the things you can do in an engineer-driven approach. These items are listed with the highest impact to effort of other people ratio at the top because we want to give you things you can do now.

#1 Read “Clean Code” by Robert Martin

“Clean Code” by Robert C. Martin is one of the top books in the Software Design & Engineering category on Amazon.com and it’s well worth the $30. This book goes over why it’s important to write code that’s easily readable and walks you through LOTs of examples of how to write clean readable code.

I wrote more about this in 5 Quick Ways to Make Your Code More Maintainable.

Criteria This Fulfills

  1. Maintainability

Additional Reading

  1. Clean Code by Robert C. Martin
  2. 5 Quick Ways to Make Your Code More Maintainable by Scott Keck-Warren

#2 Use Automated Testing

Automated testing using PHPUnit can be a huge boon to your productivity. Normal test cycles are to write some code and then manually test to make sure it works correctly. By using Test Driven Development (TDD) you write code that tests your code and the code can quickly be tested using command line tools or by using a key combination in your editor.

We highly recommend using at least one method of automated testing for your code. This allows you to quickly test your changes against all the other tests that have been created in the past and verify that you didn’t break anything you weren’t expecting.

There is a downside to being the only one to maintain a set of unit tests in a team of other programmers because other changes may cause your existing tests to fail or even break. We recommend you start with tests that operate in modules and systems you tend to “own” as this will reduce the chance of this happening.

Criteria This Fulfills

  1. Maintainability
  2. Reliability

Additional Reading

  1. “Test Driven Development: By Example” by Kent Beck
  2. “Working Effectively with Legacy Code” by Michael Feathers

#3 Ask a Co-Worker For Help

Once you start this journey you’re going to need help because otherwise, it won’t scale. My recommendation is to start by asking one of your teammates to review the changes you made and ask them to give you a lot of feedback. Hopefully, they’ll want to do the same and you’ll create a little group working towards improving your code quality. I would recommend you start out doing pull requests for your work (we’ll discuss this more later) so it’s easier to give comments asynchronously. You might also be able to work out a time for both of you to sit down and review it but that can be hard if management hasn’t given you the okay.

Criteria This Fulfills

All of them if done correctly. If the other person doesn’t buy into the concept or gets lazy it could be some or none.

The Team driven Options

Let’s say you are in charge of some programmers (maybe you should email this to your boss) or you’re part of a team looking for a better way to do things. How do you go about making changes to your team to improve everyone’s code quality?

#4 Require Automated Testing

Start mandating all of your engineers write new code using TDD. When everyone is doing this you quickly develop a large set of automated tests that prevent new bugs from finding their way into the system.

We recommend you enforce having at least one unit test for all bug tickets as well. This prevents regression bugs which can be extra annoying for your customers.

Every so often it’s a good idea to run a code coverage report on your whole test suite. This will display a percentage of the code that is being tested. This number is your code coverage percentage and it gets talked about a lot. Some people like to say that their code has 100% code coverage but this isn’t necessary and in a lot of cases it can be a huge waste of time.

My favorite example of this is the tests we have that run our reporting system. Each report gets its a test class and we mandate that the test class have a test that runs the report completely. Something like this:

public function testRunReport(): void
{
    $item = new Report();
    $this->assertNotNull($item->getReportResults());
}

This might get me to 90% code coverage for the report (it may get us to 99% code coverage). To get that additional 10% I might have to write 10 more tests to catch all the edge cases within the report (usually this is just different parameters) but we’ve found there to be very little benefit to this.

The most important thing to remember is that you’ll need to strike a balance between this number and how much time you’re will to spend on the component in question.

Criteria This Fulfills

  1. Maintainability
  2. Reliability

Additional Reading

  1. “Test Driven Development: By Example” by Kent Beck
  2. “Working Effectively with Legacy Code” by Michael Feathers

#5 Code Reviews

For the teams I manage nothing gets done without a code review. We’ve found that code reviews give us at least one extra set of eyes that are necessary to make sure our code keeps to the high quality that we think it deserves.

For this process, we use the pull request (PR) feature that seems to exist in every web-based repository hosting service these days. It’s helpful because generally these systems allow for a quick view of PRs you are working on and provide the ability to leaves comments in an asynchronous fashion without inconveniencing anyone.

You can use the built-in features provided by the repository hosting services to run your code against standard checks and even unit testing checks before you manually review the code.

Criteria This Fulfills

All of them if everyone has buy-in.

#6 Pick a Coding Standard

It’s important to pick a coding standard so your code is easier to read. I recommend the PSR-12 coding standard due to its adoption by a lot of the PHP community.

There are plugins for most editors that will highlight where your code needs to be altered to match the standard and even some that will automatically repair the files based on the rules when possible.

We also recommend using the PHP_CodeSniffer command-line tool to quickly check all of your code to make sure it’s passing in an automated fashion.

Criteria This Fulfills

  1. Maintainability

#7 Pair Programming

Pair programming is a software development practice in which two engineers work on a single task using a shared environment at the same time. This can be done either in person or remotely.

Pair programming allows you to quickly get a second pair of eyes on your code and allows you to improve your code quality.

Criteria This Fulfills

All of them

#8 Documentation-Driven Development

Documentation-Driven Development is a process were end user documentation is created by a stakeholder before development starts and the documentation is used to drive development of the software feature. This is a cost effective way to both generate documentation and generate clear instructions on what the software should do when the feature is delivered.

  1. Write documentation for End Users
  2. Get feedback on documentation
  3. Use documentation to generate automated tests
  4. Code review
  5. Push changes to staging
  6. Deliver feature and publish documentation

Criteria This Fulfills

Purpose

Conclusion

Hopefully, this article helps you and your team improve your code quality. If so let us know in the comments below.