Showing posts with label best practices. Show all posts
Showing posts with label best practices. Show all posts

Sunday, 16 March 2014

Code Quality - Refactoring

Question:

My project team has been asked to improve code quality by performing refactoring. I know that code refactoring is all about reviewing the code and ensuring that it follows the best coding practices. I however seek your guidance as to what are the aspects one should look into while performing code refactoring and also point me to some references, where I can learn more about the same.

By: Rajesh Dhawan


Answer:

Your question has the answer to some extent. Martin Fowler and Kent Beck originally defined refactoring as "a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior… It is a disciplined way to clean up code that minimizes the chances of introducing bugs". Refactoring can be as minor as an inline change or it could be a massive code rewrite. Though large scale code refactoring can be an architectural redesign, as long as it does not change the business logic and when it is done in steps, it can be called as refactoring as well.


This is mostly done to improve the non-functional attributes of the program thus leading to improved code readability and maintainability. The design priorities or constraints for the enterprise applications are usually defined by the Enterprise Architecture teams, considering the vision, mission and goals of the enterprise and in turn the IT organization. Having said that while refactoring is all about making code changes to make it conform to the non functional attributes like maintainability, scalability, performance, etc, the specific design best practice or design pattern to consider would differ case to case.


Ideally, refactoring is done in iterations and technically there is no end to refactoring. However, one can say that refactoring ends when the code becomes 'simple', in which case, the definition of simple is subjective. As a programmer, you should be able to smell your code to figure out whether it needs refactoring. Here are some situations when your code smells, inviting you to refactor:

  • Duplicated Code - extract out the common bits into theirown method (extract method) if code is in same class if two classes duplicate code, consider extract class to create a new class to hold the shared functionality.
  • Long Methods - extract method!
  • Large Class - Class trying to do too much often shows up as too many instance variables.
  • Long Parameter List - replace parameter with method (receiver explicitly asks sender for data via sender getter method) Example: day month, year, hour minute second ==> date
  • Divergent Change - If you have a fixed class that does distinctly different things consider separating out the varying code into varying classes (extract class) that either subclassor are contained by the non-varying class.
  • Shotgun Surgery - The smell: a change in one class repeatedly requires little changes in a bunch of other classes. try to move method and move field to get all the bits into one class since they areobviously highly dependent.
  • Feature Envy - Method in one class uses lots of pieces from another class. move method to move it to the other class.
  • Data Clumps - Data that's always hanging with each other (e.g. name street zip). Extract out a class (extract class) for the data. Will help trim argument lists too since name street zip now passed as one address object.
  • Switch (case) statements - Use inheritance and polymorphism instead (exampleof this was in Fowler Chapter 1; this is one of the more difficult refactorings)
  • Lazy Class - Class doesn't seem to be doing anything. Get rid of it!
  • Speculative generality - Class designed to do something in the future but never ends up doing it. Thinking too far ahead or you though you needed this generality but you didn't. like above, collapse hierarchyor inline class
  • Message chains - Say you want to send a message toobject D in class A but you have to go through B to get C and C to get D. use hide delagate to hide C and D in B, and add a method to B that does what A wanted to do with D.
  • Inappropriate Intimacy - Directly getting in and munging with the internals of another class. To fix this, move methods, inline methods, to consolidate the intimate bits.
  • Incomplete Library Class - If method missing from library, and we can't change the library, so either: o make this method in yourobject (introduce foreign method) If there is a lot of stuff you want to change: o make yourown extension/subclass (introduce local extension)
  • Data Class - We have already talked about this extensively: in data-centric design, there are some data classes which are pretty much structs: no interesting methods. first don't letother directly get and set fields (make them private) and don't have setter for things outsiders shouldn't change look who uses the data and how they use it and move someof that code to the data class via a combinationofextract method and move method (see the Fowler chapter 1 example for several examplesof this)
  • Comments - Comments in the middleof methods are deodorant. You should really refactor so each comment block is its own method. Do extract method.

Check out the following to know more on the subject:

Sunday, 26 January 2014

Continuous Integration in Agile Software Development

Question:

I am a fresher and have recently joined an IT firm as a .NET developer. After 15 days of orientation and training I am not part of a project team. I have been hearing a lot about Continuous Integration. Can you help me understand what it is and how does it help the project execution?

By: Rajesh Narayanan

Answer:

One of the important reason behind the software project failure was that the defects or issues discovered in the later phases proving to be too expensive to address and thus adding to the time and cost of the project. The industry has come up with different methodologies to address such issues and thus Agile Methodology has gained much adoption and recognition. As you may be aware, one of the key principles of Agile is to put in processes and techniques, so that the defects or issues are detected early on and thus giving opportunity to address sooner. Practices like SCRUM, Pair Programming, Test Driven Development are all expected to address this issue of catching the defects early on. On the same lines Continuous Integration and Deployment also contributes towards offering an opportunity to discover issues early on by offering the customer a working software product every now and then.

Traditionally, developers work on building components or modules independently and there will be a phase which will be fairly closer to UAT for integrating these modules together. No wonder, the development teams will discover many inconsistencies leading to the modules not working in tandem as intended. This calls for rework on one or more of the already built modules.

Continuous Integration addresses this problem by ensuring that every time the developer checks-in the code changes, the code modules are integrated with other related modules and deployed as well. This activity is best achieved by automating the build and deployment process. That means, the developer as he checks in code changes, will see the build and deployment errors and or warnings, which are expected to be resolved then and there, so that every code change that is checkedin does not break the working product. Thus the end customer will be able to see a working product always and able to validate the change as it is implemented.

The following are some of the key practices that makes the Continuous Integration workable and useful as well:


  • Maintain a Single Code Repository - Continuous Integration won't work if developers maintain isolated code repositories for different component or modules. There are plenty of open source and commercial source code control tools that offers robust conflict resolution techniques and facilitates usage of single code repository.
  • Build Automation - The Continuous build and deployment activity is best accomplished by automating the same. Most of the programming languages support this requirement and tools like CruiseControl are also very useful to accomplish this.
  • Test Automation - The automation process shall also execute the basic tests by itself. this where Test Drivent Development is in use. The developers, as they write code are also expected to create test scripts, so that these will also be executed during the automated build process.
  • Frequent Code Commits - The developers should commit the code more frequently and at the least every day. They should commit the code after every logical completion of a code change, so that the build does not break. This where, the Agile principles revolves around braking the coding tasks into smaller units, so that such tasks typically take 8 or 16 hours to complete.
  • Automated Deployment - Coupled with build automation, the code should also be deployed on to the test environment, so those involved in testing see the latest changes as soon as they are committed into the repository.


Hope the above explains the purpose and the principles of Continuous Integration. You can look up Martin Fowler's article on the subject to know more.