Having started, come back to, taken over, and been overtaken by many long-lived applications, I have found some common practices that makes navigating these brown-fields easier and much more enjoyable. This article will focus on working within long-lived applications and not replacing them.
While some implementations seem crazy, there was a reason why they were done. Sometimes the reasons were good, sometimes not. Most of the time, the reasons have changed and have been lost to history.
Warning, Preaching Ahead
It is best to focus on what is there and how to move forward, not look for blame or put down others' hard work. Having a positive approach can make all the difference in the world.
Learning the Landscape
Whether I am new to the project or the one that shoulders all the blame, I try to look at it with fresh eyes. I am quiet and absorb as much information about the current state as possible. Keeping in mind, many of these things have changed over the course of the application's life.
Start with the “why” of the project. Why is this solution needed? What problem is it trying to solve? Who is using it, and how are they benefiting from it? I do this from a very high level to set a foundation in my mind. This frame of reference gives a lens to absorb the rest of the information.
Next, I look at the current solution from a technical standpoint,. This means reviewing the interface, architecture, code, tests, documentation, etc. Again, this is done from a high level. I am not evaluating individual files or lines of code. I am trying to form a holistic technical picture.
The last step of learning is all about the people involved. I want to know who is invested in what and how they interact with each other. I do this from a desire to help empower everyone. I don’t want to come in and make drastic decisions or changes that will cause more frustration. Working together toward a shared vision will allow the prickly brown field to slowly turn into a field filled with flowers and happy little trees… that make happy little mammals… which is the people… where was I going with this.
Cultivating the Fields
To have a good foundation for improving, the team needs a good set of tools to accomplish their given roles. These tools can cover a wide range of topics, including project tracking, release management, development/testing environments, production monitoring, etc.
Start with small wins, like adding a shared set of linter rules. Maybe take on bigger items as the team sees the benefits. Improving the developer/team experience can greatly enhance the overall happiness.
Next is digging into the code a little deeper. I want to approach changes to the code in a way that doesn’t shock the system or the team. These improvements should happen as different parts of the application are touched for feature enhancements/bug fixes. Rarely do I start working on a piece of the codebase that needs no change, just for the sake of improving the code.
After reviewing the code, I find little seeds in the code to help grow into real improvement. This could include:
- Test coverage
- Performance enhancements
- Reducing duplication
- Removing unused code
- General code quality
With a general list of things to tackle, I take this to the team for consideration. I want buy-in and excitement that we are making things better together. Getting ideas from everyone involved on ways to improve can go a long way to help positive growth overall.
Getting everyone involved at the start is great, but a plan is needed to really gain continued improvement over the longer term. You can’t just throw those seeds anywhere and water them randomly. What better way to ensure continued improvement than fertilizing the ground from which all things grow. I may be taking this farming analogy much too far.
Starting with training any technology or work-flow that might be new or confusing to the team. These are usually informal lunch-and-learn type deals, but whatever works best for your team.
I want to make sure there is consistency between everyone, and our agreed-upon list of improvements is being followed. If there wasn’t already a code review process in place, I definitely push for one. This will allow both the original coder and the reviewer to develop an agreed-upon common language spoken through the code.
Depending on the team and management structure, pairing is a great tool to quickly spread knowledge and validation of the improvements. There is a natural buy-in that happens when people work together. They usually come to this shared language much quicker than if just code reviewing.
Once the team comes to an agreement and everyone is ready to start implementing, I dive into the work. I always start with test coverage. I want to know what I am changing is not affecting the existing implementation. I then work on the implementation of the feature or bug fix taking into account our agreed upon improvements. I usually finish up with my favorite part, removing code. This could be removing duplication or removing unused code. Removing the dead things so the new things can grow. So satisfying.
As the changes happen over time common patterns will emerge. Components can get pulled out into a centralized system for ease of reuse. Then continued implementation using these centralized items will accelerate the conversion from prickly brown field into a thriving fruitful field.
While the process will take time and can be difficult, it can make a world of difference to the quality that is being turned out from its harvest. Plus the people working the field are much more likely to enjoy the fruits of their labor.