I’m a big fan of TDD. I will try to put as many tests as I can on my projects. However, I’m still in learning phase. There are lots of things I still need to dig up in PHPUnit. While I’m at it, I discover something called as code coverage. Code coverage is a way check on how much the codes inside your project are being tested. Usually code coverage will give a report that contain lots of statistic about the code that being tested. One of the interesting metric for me in that report is C.R.A.P. Index.
What is C.R.A.P. Index ?
According to Alberto Savoia:
The C.R.A.P. (Change Risk Analysis and Predictions) index is designed to analyze and predict the amount of effort, pain, and time required to maintain an existing body of code.
Basically it’s a number designed to highlight potential problem areas in the code you’ve written. The higher the number, the crappier your code may be and the more likely it should be reexamined and refactored.
Testing This Theory – Write Some Crappy Code
Setting up files
Before we test that theory, we will need to set up our project. For this tutorial, i will use Docker to run the application – so you might need to install it on your machine. The project will contains these files and folders :
Project tree structure
After setting up those files, run these commands to install all the packages needed for development.
Run the code
After installing the needed files, run this command to start the application.
Write the code
Write a sample class to test – app/CrapClass.php
Write a test class to test the sample class – tests/CrapClassTest.php
Run the test
After we done write the test and the class, run this command to run the test and generate the code coverage report.
Checking up the first result
After PHPUnit done running the test, check the report inside tests/coverage_results folder and click on CrapClass.php.html file. You should see something like this.
As you can see, the CRAP index value is 42, which is pretty high. We can reduce it by completing our test.
Completing our test
Now reopen the tests/CrapClassTest.php file and update it with the code below.
Rerun the tests
Checking up the second test result
As you can see above, now the CRAP index is on 15.28. Plus, there are few lines not executed yet. We can reduce the CRAP index more by adding more data to test all the scenario.
Adding more scenario to our test
We can reduce the CRAP index by adding more scenario to our test. We can add the data and test for the Exception. Open our test, and update it like the code below.
Rerun the tests
Checking up the test for the third time
The value is 6 now, great! Our class also seems have 100% coverage which is pretty nice in this case ( 100% is not always a good number, sometimes there are class or file didn’t need test – read more here ). But we can reduce it more, by refactor the class code.
Refactor the class
Now lets refactor our class to make it more clean. Open app/CrapClass.php file and update it with the code below.
Rerun the tests
Checking up the test result for the fourth time
Look at that! The value is 2 now ( for listCities method ), which is a nice number. Seems like the code is more maintainable now too.
First of all, this post was inspired from this post. There are some changes on the source code example, but the idea is still the same. I also agree with the final thought part in that post, thus i will just copy it over here.
While lowering the C.R.A.P index of our code is always a good goal, it can easily create more problems than it solves. Refactoring your code just lower a number on a report is never a good idea. By arbitrarily lowering the C.R.A.P index, or any other programming metric for that matter, you not only go against the metric’s original intent, but you add an artificial and unnecessary complexity to your code that could end up doing more harm than good:
software metrics, in general, are just tools. No single metric can tell the whole story; it’s just one more data point. Metrics are meant to be used by developers, not the other way around – the metric should work for you, you should not have to work for the metric. Metrics should never be an end unto themselves. Metrics are meant to help you think, not to do the thinking for you. ~Alberto Savoia