I am going to talk about some common sense approach to code quality, ie. Code sense . How we can take some basic measures to make sure that the code we write is of sufficiently good quality and that makes sense to us when we come back to it after a week, month or even to any one new to that code.
And I will be using ruby to demonstrate that because I use ruby to code and I think it is an elegant, very flexible and pure object oriented language. Everything in ruby is an object even the integers. What that means is you can pass messages to integers, i.e. call methods on them for exampe
Integer 12 is an instance of class Fixnum. I can pass it messages like class to find out what type of object it is, modulo, to_s and to_f to convert it to string or float. This looks and sounds very simple but if you think of it then this becomes very powerful when it comes to do metaprogramming i.e. programs that can generate programs dynamically. Thats enough for ruby, if you want to know more about ruby then catch me after the talk
I am gonna talk about how to write good quality code but that doesnt mean that I always write perfect code. I do slip to the dark side but every good programmer knows that they rarely write good code in the first instance. I will come back to this later during my talk.
Measuring code quality is very subjective because the code that is of sufficiently good quality for me may be of very bad quality for someone else. You can only measure code in relative terms. Though there are tools available to check the cyclomatic complexity, code duplication, test coverage, structural similarity, etc. For instance, in ruby world we have a library/gem available called metric_fu that people who care about code quality use to get some metrics on code. Can anyone give me some idea like given some code how would you measure its quality I think the image on the next slide shows the best way to measure code quality.
Show code I will show you some code that has been used on an ecommerce site for subscriptions.
The moment you see any of the above in a code then that is a target rich environment for bad code.
However bad, a code is, If it is in production then no one would touch it unless there is a requirement to change its functionality. And the rules of economy dont permit that as well but it shouldn't have been there in the first place So this code has been working fine doing automatic renewals of user services but now lets say we want to add auto renewals for some new products that have slightly different requirements or process flow.
If you don't care about your code quality then what you are gonna do is bodge in another if / switch statement somewhere in the run method and job done. DBAD = Don't be a dick
Number of time people say that they are refactoring but they are actually changing the code while adding new functionality which is a bit dangerous because you might introduce bugs while doing that. So hold on your new functionality and first refactor the code. The main ingredient of refactoring is to have unit and integration tests. If you already have them then go ahead changing test as well as code else first add the tests so you know when you break anything,
Once I found some bad code that I thought needed refactoring. That code started doing something very simple about few months ago about showing different messages to users when a user request is complete. Sounds simple but it became a bit complicated after we added a background worker that will process the queues. Sometimes queues get held up due to some reason or the other. And then you need to show different messages to the users. So we passed different parameters to the redirected page and on the controller action of that redirected pages we ended up adding so many if / else statements to show different messages based on the presence of different parameters I was about to modify something and I saw that and said to myself F*UGLY. - discussed, lunch,back, got an idea, show n tell, discussed about the schedule, implemented
So I refactored the code and one of my colleague also pitched in during final stages of refactoring that basically led to this,
Should be small Named appropriately Do onlly one thing Should be at the same level of abstraction Should use minimum number of parameters
Some ruby code What do you think about this code?
Problems in the code <ul><li>1. Too many private methods </li></ul><ul><li>2. The method Run is too long </li></ul><ul><li>3. The run method is doing too many things </li></ul><ul><li>4. Difficult to reuse </li></ul><ul><li>5. Due to all the above reasons it is brittle and difficult to test </li></ul><ul><li>6. Redundant comments </li></ul><ul><li>7. Not DRY </li></ul><ul><li>8. etc </li></ul>
Add new functionality or change the flow of the same code
Options <ul><li>Create a new class, copy the whole code and change the bits that vary – DBAD, Don't do that </li></ul><ul><li>Add some if / switch statements in between the code and get it working – DBAD, Don't do that </li></ul><ul><li>Refactoring </li></ul>
Refactoring Change internal structure of the code without changing it's observable behaviour.
Why refactoring? Any code that is difficult to understand and restricts adding new functionality to it or extending, needs refactoring.
Comparison <ul><li>Previous code </li></ul><ul><li>1 class </li></ul><ul><li>2 public, 7 private and 0 protected methods </li></ul><ul><li>244 lines of code </li></ul><ul><li>Plus all the bad things specified on slide 8 </li></ul><ul><li>New Code </li></ul><ul><li>3 classes </li></ul><ul><li>30 public and 0 private/protected methods </li></ul><ul><li>300 lines of code </li></ul><ul><li>Plus almost all the goodies from the next two slides </li></ul>
Basics <ul><li>Small methods </li></ul><ul><li>Single responsibility, i.e. separation of concerns </li></ul><ul><li>Naming variables, classes and methods appropriately </li></ul><ul><li>Test Coverage </li></ul><ul><li>Simplicity </li></ul><ul><li>Don't pass too many parameters to methods </li></ul><ul><li>Comments – don't pollute code with useless comments </li></ul>
Basics <ul><li>Keep it tidy, i.e. create methods where they are supposed to be </li></ul><ul><li>Keep it clean, i.e. remove commented out code, add proper indentation, etc. </li></ul><ul><li>Check your code quality before committing / pushing your code to repo. Stop if you have degraded it </li></ul><ul><li>Discipline: Follow the above steps rigorously or any other you have. </li></ul>
Thank you Q? twitter.com/_nasj nasir.wordpress.com github.com/nas stackoverflow.com/users/200486/nas