Here I am, back after more than a month publishing the first golden rule. I said to myself today that I should keep up to speed with this subject in order to finally end-up with a good number of rules as I find the exercise interesting and opening great paths for thinking and reflecting on limited but compelling subjects.
So the Golden Rule #2 is about refactoring code and software architectures. One may wonder: "Why are you talking about continuous refactoring as a Golden rule??!! After all if you follow development best practices and apply all golden rules, aren't you then expecting that the design and code produced are of good quality, therefore not requiring refactoring?!"
Introduction - what is all the fuzz around refactoring?
Refactoring is often associated to "repairing" legacy code or poorly designed applications. Even though it is sometimes what refactoring is used for, refactoring is also first class citizen of a full agile process of developing high quality applications. I would even go one step further: if a reasonable sized project is achieved with no refactoring phase during its implementation, then there is probably something wrong and a flawed underlying design that will bring you trouble on the path ahead.
Software development is a complex discipline, and the vast number of patterns, tools, frameworks and best practices leads to numerous ways for implementing one scenario. It is all about pros and cons, compromises, and identifying the potential future points of evolutions of the business need in order to be ready for it.
Even though it is always recommended to do a design first and coding later, I don't believe one could or should do a fully detailed design before writing the first line of code. The key winning idea is to be pragmatic, agile and iterative. Any design should be validated by proper implementation and validation, to then be adapted, enhanced and implemented again. There is a limit to paper diagrams and even experienced designers cannot fully predict the behaviour of the future implementation of there designs in terms of performance, security, usability and fitting in the target infrastructure, nor can predict that the frameworks and techniques that they theoretically plan on using will actually be relevant perform/provide a service as excepted; one exception is if they already designed and developed a very similar application, following very similar constraints and non-functional requirements, and targeted to a very similar platform. Added to these technical only aspects, business needs can also evolve, during the lifecycle of the project, get re-scoped and adapted and therefore require changes in the application technical design. The consequence of this is that refactoring phases will be mandatory to iteratively build the software solution.
Another point is that a successful software architecture and design is the result of a collaborative work between several people, architects, analysts, and developers. So, all participants should be involved in the process as soon as possible thus requiring starting the development phase early for efficient and productive feedback from the development side ASAP. As a consequence, refactoring phases will have to be planed and performed until reaching an acceptable quality level.
So why do you need refactoring?
Including refactoring phases in your development process and lifecycle answers to the following needs:
- You need to make sure that your software design and architecture properly address evolving business needs: Refactoring phases can be necessary if a major business evolution requires rethinking of part of the design of the application. The application should always be designed with flexibility in mind and requires that aspects of potential evolutions are properly identified to know where to design and build flexibility.
- In an agile process, refactoring is an essential technique to iteratively build the most appropriate software architecture and design, while gaining in maturity iteration by iteration. This is a key for agile development where functional slices of the application are frequently delivered and most of the times require partial refactoring to move from one iteration to the other and increase quality and relevance of the design.
- Late discovery of functional or technical constraints can lead to the need for a partial refactoring of the application to address this unexpected event. By the way, an agile, highly iterative process can help reducing the risk by early addressing all the aspects of the application, and especially the aspects that are considered high risk.
- Results of test campaigns can reveals areas that need refactoring, for either technical reasons (poor performance, low scalability, etc.) or functional reasons (inappropriate functional behaviour revealed by the UAT that has an impact on technical design). Again: and agile iterative process will help address early these issues.
Rigorously including refactoring phases in your development process will therefore help you increase the quality and relevance of the overall application design, making the application more maintainable, robust and flexible. Moreover, being able to regularly and efficiently perform refactoring sessions without breaking the whole application and entering uncontrolled regression phases will be the undisputable proof that your software design is effectively of high standard.
Can I include refactoring in my development process seamlessly and for free?
Ok, refactoring is not a simple thing and it is definitively not a painless, safe action to perform if you are not prepared for it.
First condition to include regular refactoring phases as part of your development process is to actually have a well designed and architected application. And refactoring becomes a way to iteratively increase the quality of this design. But you can't apply proper refactoring as part of the development process for commando like or any other kind of quick and dirty type of programming.
Second condition is that you should have a proper set of unit tests covering your full code base. Refactoring is about rewriting and restructuring code thus meaning creation of new bugs. And you don't want to break what was working before. Therefore a set of unit test with high code coverage will help you (yet not always suffice) verify the quality of the refactored code and make corrections if required. Important refactoring will also require the re-writing of the unit tests, which is ok: just make sure that your new set of unit tests still covers the same functional use cases.
Refactoring can be painful if you don't have the proper tooling to assist you and automate repetitive operations. And the pain can be even worth if you need to refactor across several projects. Visual Studio includes basic refactoring tools that are really useful and a big step forward since version 2005. But you can go even a step further and use commercial refactoring tools. The one I use (and love!) is ReSharper, and you can read my post about it for more details.
Another thing you need is a refactoring compliant source code control system that allows you to seamlessly move and rename files while keeping the integrity of source code repository and version history. And I haven't found such a tool yet. To be honest I haven't tried too many tools as I am quite happy with the Microsoft Team Foundation Server package for building a full continuous integration environment. Unfortunately, TFS does not quite like renaming and moving files and can act weird when you try to do so. For large refactoring, the solution is to start on a new, clean TFS project that is built on the new file structure implied by your refactoring. You still keep the full version history though the previous TFS project but lose the connection with your new project. Another advice to limit the issues you can have with your source control while refactoring is the following: try to avoid to a too deep hierarchy of projects, trying to mirror the namespace tree. Just save your projects on a flat, or as flat as possible, file structure. You still can have a hierarchical view in Visual Studio by creating solution folders. This way, it will dramatically make moving or reorganising namespaces much easier! Don't forget that reorganisation namespace is one of the most common thing you will do while refactoring...
Last point to mention is that it will be useful to have an automated process for updating documentation. Refactoring implies changes in the documentation and documentation is not a good candidate for manual update because it will then never be updated. Solution for the documentation is the use of tools that automatically reflect on the code comments to generate the detailed documentation. So rule is: comment properly your code and run a tool on your code base. The tool I use is Sandcastle. And for more high level class diagrams, you can choose a UML tool that can reverse code-engineer UML diagrams from you code. Visual Studio embeds one very basic tool. I personally use Enterprise Architect that I will describe in a future post. Key element is that you should be able to automatically update the technical documentation if you want to have technical documentation at all!
So am I ready to go?
You must be aware that refactoring cycles are time consuming, require courage and patience for the extra effort induced. It therefore requires discipline and a well accepted and applied process that includes these "technical" refactoring phases, apparently not bringing any additional features or business value, but really mandatory in the medium to long term for creating a robust and flexible applications. Therefore the sole idea of technical refactoring being part of the software application development lifecycle is something that needs to be strongly supported by the project management board, and more importantly: really applied during the project lifetime. And this is probably the most difficult part as management teams can have difficulties understanding the need of spending a lot of time, effort and money for something that apparently (but apparently only) does not bring any added value to their business application. And this difficulty can be caused by a lack of understanding of both parties and a low trust given to others.
This leads us to another Golden rule on which I will write later. This Golden rule is not really a development golden rule but a more high level, project level, strategic golden rule: go for collaborative and responsibility driven team organisation rather than for a hierarchic centric organisation. This rule says the following: to make a project successful (be it a software project or any kind of project BTW), you should build a team with well defined responsibilities and skills and trust everyone in the team for his/her competencies and believe and take into consideration the well-founded of their advice. This is the best and more human way IMHO to have a real success on your projects and long term involvement and efficiency of your overall project team. But more on this later, so keep connected to the Golden rules series!!
Recent Comments