Chisara Nwabara
In many ways, working on a legacy project is much more challenging than working on something fresh. You are dealing with an old dog; a creature that is less malleable and, in my experience, often times less willing to take on new tricks when push comes to shove. It takes a lot of patience and also an understanding that even though this dog is stuck in its ways, it has years of experience that should not be overlooked.
So, in my opinion, the challenge is determining how best to leverage said experience so that it can be applied to the practices you’d like to bring to the workbench.
Once you are able to balance the your knowledge/experience with that of the client's, the project goes much better.
Linda Goldstein
I am currently on a Java project that started before Java had non-generic lists. Last month, we had to code around a bug in Java that was fixed in 2011. There are code comments from 2002. At least three different editors, with three different code generation and indentation styles, have generated code in this app. There are both DOS and UNIX line endings. Using Vector was considered good practice at some time during the lifecycles of this app. As far as I can tell, at no point has dependency management been used; all the jars are checked in.
Legacy is a challenge. You can never fix everything all at once. And what I consider a 'fix' may break something that was written several years before I learned how to code. In order to actually understand what you're doing, you have to learn not only what is a bad idea today, but why it was a good idea five years ago.
"Learn from the mistakes of history, or you will repeat them" is the common wisdom- but, like the prime directive of retrospectives says, "Regardless of what we discover, we understand and truly believe that everyone did the best job they could, given what they knew at the time, their skills and abilities, the resources available, and the situation at hand." Those mistakes of history? A lot of them weren't mistakes. They were conclusions given a different data set than we are currently operating with.
Working within legacy constraints is a complicated puzzle. On this project, I get to make something more elegant every day. There are a lot of low-hanging fruit. It's not boring yet.
When it comes to how working on a legacy project affects my interactions with people... there is fear in this codebase, and you can smell it in the null checks and in the comments. There are too many unknowns left over from 2004; there is too much "just in case" code. I write it too; the fear is justified. The test coverage is low, and you can never be quite sure what the code upstream will do, since the Single Responsibility Principle was not (and is not) always universally approved of.
A legacy project is a complicated ecosystem in every way; it is very far from the relative simplicity of "rails new testproject" and I do sometimes wish that the only code we had to contend with on this project was written by people using the same approximate temporal set of best practice references as we.
Sarah Hutchins
I have never honestly worked on a legacy codebase. Even now, my current engagement is around teaching the client a better way to write code and the codebase is little more than an example minefield. However, I have been on the other team - the ones from whom you inherit the code, the ones who have to somehow impart all the knowledge built up, the ones who made those decisions which come back to haunt the project.
It is very easy to start out with good intentions and watch things slowly unravel. Between business indecisiveness, lack of experience, and the odd technology choice for which there is no choice, compromises end up finding their way into the codebase. The more functionality which gets added, the more cluttered the domain model became. Pressures make it difficult to do a domain model level refactoring and before you know it, our greenfield project became just another cluttered codebase.
Ramping people up in this situation is never pleasant, and unfortunately, the second wave onboarding tends to be roughest. No matter how much you try to cover when explaining things, there seems to always be that one class which gets missed or that one testing standard. Furthermore, as one of the original members, so much of the knowledge has become second nature it becomes difficult to ramp up someone from nothing. It is one thing to claim you need to tell them everything and quite another to actually do it. After all, how would you explain walking? It is a skill we learn through trial and error over a period of time and we constantly refine it as we use it. We get to the point where we can no longer consciously remember everything involved in it because the knowledge is ingrained. After being on a project for a couple months, it can feel like that. As a result, a lot of pressure ends up on the one getting ramped up since they have to ask questions about the knowledge you do not even think about anymore. Naturally this can lead to frustration over the seemingly convoluted codebase. Then, as the original team, you watch the new people come in and decry many of the decisions made without knowing why the decisions were made. Things start to get added to the codebase without the context of the old guard and it becomes even more disjointed.
This is not to say new people being added is a bad thing. It is a very good thing as new thoughts and ideas are added. The new people are also not weighed down as much by the knowledge of the past and will have a much easier time questioning decisions. Cycling in new people is one of the better ways to keep a project innovative and without the new blood, it is very easy for a project to stagnate. Furthermore, once you get through the second wave of onboarding, ramping up those who follow can be quite a bit easier. At this point you have both the originals who have the context and the second wavers who had to struggle through and can remember their difficult spots. Later ramp-ups can take advantage of both to not have to figure out all the right questions since the previous group has already been there.
Abby Bangser
While I do not think all “legacy” systems are the same, often people associate legacy code with a buggy, hard to understand code base with limited test coverage. If we look only at a situation which falls into these categories it can be a very difficult situation for a new Quality Analyst to roll on to. How do you test something that even the most project experienced testers and developers do not fully understand? Questions abound, including...How can we be sure this change doesn’t cause a bug somewhere not immediately obvious? Was this an existing bug or a new one? Where else does this change show up?
However, what I have found is the biggest struggle is not in the risks, but in redefining the concept of a “quality product” in the eyes of the customers and development team. Obviously the current team takes great pride (and should) in their product and the customers rely heavily on the application. However, everyone from developers to users have learned (and I quote) “work-arounds to work around their work-arounds”. This deep understanding of already unsteady processes leads to a desire for consistency even when it perpetuates the acceptance of bugs and hardships for the users.
There are ways to introduce change by deciding today that anything new will be written under the new standards, and to refactor existing code in a slow by steady manner. The fragmented and duplicative nature of legacy code can make it difficult to change existing functionality that spans lots of the application (ie: a standard for how to submit a form which may not be user friendly but is “copy and pasted” around to many screens). By building any new versions with modular pieces you can kickstart the refactoring process and before long have all instances called from the same method which allows for a one step change. This consolidation of changes is more likely to be approved by the customers since consistency will be maintained.
No comments:
Post a Comment