Refactoring: Communication and Time

A recent lunch led to a great conversation about refactoring other developers’ code and when it is reasonable to do so. Generally, I believe it's unwise to refactor other developer's code without talking about it first. Especially when the code you want to refactor is a peer or a lead. We came to a conclusion that it is fair to refactor without comment when you are under a tight deadline and its the only way you can see to fix the problem.
First, I really don't like refactoring someone else's code if that person still works at the company. It can be seen as a vote of no confidence and a real ego bruiser. Even the worst developer still takes pride in his work and making that person upset or angry does not make your project go more smoothly. Discussions, mentoring and positive criticism will often get the point across and the person learns how to write better code.
There are still times when it is reasonable to go ahead and refactor the code without warning. Let's say you are working the weekend to hit a deadline and you have to make sweeping changes to someone else's code and you can't get in touch with him. This scenario happens in somewhat older projects where the old code has been patched over and over again. It was good code once, but the application has grown beyond the algorithm. The best way to fix it is to rewrite it into clean code that fits current requirements.
Hopefully you have a good understanding of what the code is supposed to do and can write one or more replacement methods that adds new functionality while faithfully recreating the old. It is very easy in these situations to regress. At this point, the best thing to do is to test, commit the code and then tell the developer responsible for code about what you did and why. Most people will be gracious and happy that you fixed what was probably seen as a burden. Other developers may get really crabby or even yell about the changes. However, hitting deadlines is often more important than personal egos and real pros are often ready to accept that.
Another scenario is when you are the lead developer and you have several people churning out code for a set of features. Sometimes you have to integrate all that code which often requires some measure of refactoring. You may see, for example, that an algorithm is simply incorrect and will not operate correctly. If you have time, you should bring it to the attention of the responsible developer and communicate the problem. If a deadline is looming then you are probably better off just making the changes and telling the person about it later.
Clearly, there are two common themes here. The first is that communication is critical, whether good or bad. The idea is to drive home why you made changes to explain your point of view and hopefully get buy in. Its also the opportunity to find out whether your change is really appropriate. Sometimes the refactored code is worse because it introduces regressions in other concealed areas. The owning developer is often the only person that knows about these other dependent components.
The second theme is time. The tighter the deadline, the faster you have to move. Missing deadlines can impact sales, support, documentation, QA, salaries and staffing. This may sound a little over the top, but many customers only budget and buy during certain times of the year. Missing a customer's budgetary or buying cycle can mean missing an entire year's worth of revenue from that customer. Small companies with few customers are very sensitive to losing revenue. Consequently, slipping a date because you didn't want to modify someone else's code is usually not helpful.
Communicate and delegate when there is time and refactor carefully when there isn't.

The End-To-End Developer

The end-to-end web developer is a rare find though it would seem like she should be all too common. The term refers to developer that can write quality code at every tier of a web application. For a Java developer, that means being able to write good HTML, Javascript, CSS, JSP, Servlets (though they appear in many forms), EJB (and their various kinds), JDBC (or Hibernate), SQL and a little system administration too. It sounds like a common set of skills and many employers claim to require them, but often these skills are difficult to gain and some jobs make it difficult to practice.
Before I dive into the ethereal land of opinionated-qualification-make-believe, please consider how your company divides its teams. Many companies have their developers work on specific tiers of the application. Some developers work on the UI, others write EJB services and some focus on database development. Employers may want to see a wide range of qualifications on a resume, but may quickly lock a developer into a specific tier or role that doesn't take advantage of those other skills. This organizational style also makes it difficult to grow skills outside of a developer’s immediate role.
Another style operates on a functional slice basis. The concept is that a developer is responsible for one or more features and writes the UI, middle and back tiers. Obviously, this organizational style takes advantage of the developer's entire range of skills. This style does not preclude specialists, such as expert UI and database engineers. The specialists may do fit-and-finish work, perform design reviews and set the direction for the particular tier. A developer in this organizational style is able to practice a wide range of skills daily.
The first approach encourages specialization and the second is generalization. An end-to-end developer coming from the first approach may have some skills but was afforded limited opportunity to grow them. The multidisciplinary requirements of the second approach requires a lot of upfront knowledge that is difficult to attain without being in such an environment previously.
Back to being an end-to-end developer. Why are end-to-end developers valuable? Startup and small companies often have a wide range of development needs but may lack a significant budget to hire specialists for each tier. Generalists fill those gaps though they can command a higher initial salary, they are still less expensive than hiring two or more specialist developers.
Are generalists more skilled than specialists? This is an extremely difficult question to answer. Specialists are focused on a given subject and should be more knowledgeable on that subject. Yet a generalist may have actually worked with that technology for longer and at a greater depth than the specialist. An example of this is a UI specialist with two years of Tapestry experience compared to a generalist with four years experience in the same technology.
Years of experience is not necessarily an accurate gauge of the developer's depth of knowledge though. The only way to tell if a developer has the experience necessary to do the work is by probing through the interview process. This is necessary when dealing with generalists and specialists alike.
The generalist vs specialist argument is one of personal choice and there is no right or wrong answer. There are advantages to both and the rule of staying current with evolutions in technology remains the same.
The concept of the end-to-end developer is fascinating as the developer should be able to write an entire web application on her own. Such a developer is proven when she has actually built something on her own and made it publicly available. It doesn’t need to be earth shattering or massively successful, it just needs to solve a problem and be accessible to the world.
But there are other, less obvious skills being learned too, like self-determiniation, time management and follow-through. Many job descriptions look for a self-starter: some go-getter developer that can work with little supervision, lead a team and finish what they agreed to in a reasonable time. If a developer spends the time to learn to every tier of web application development, builds something and makes it public then she meets pretty much all the listed requirements except for leading a team. Thankfully, team leadership is a learned skill.
One item that should be clarified is the difference between the hobbyist and end-to-end developer. There is a reluctance to hire a developer that learned specific skills through a hobby project rather than a commercial project. There are some good reasons for this, such as hobby projects usually don’t require a developer to focus and develop a project for eight, or more, hours a work-day. It’s hard for a developer to gain breadth and depth, in a vacuum, working on a hobby only a few hours a day or week. The big difference is that a hobbyist doesn’t have to finnish, the end-to-end developer does and then works harder on it and makes it into something big.
It would be reasonable for someone to look at this and say “he’s just trying to justify hobbyists.” There might be some truth in that. Yet look out at the successful sites and think about how many of them emerged from little more than hobbyist developers. How many blogs are little more than hobbies and yet we glean great information from them. A big difference between the hobbyist and the end-to-end developer is that the former is interested in learning something but has no real goal beyond that while the latter has a goal, finishes and makes it public.
Finishing makes the difference.

Criteria for Selecting Technologies

Every developer starts out simply being told which technologies he will use, but it doesn’t take long before he can choose his own destiny. Selecting technologies for a project is surprisingly difficult. Some technologies are incredibly good for a specific set of tasks but become equally cumbersome or even unusable when you go beyond those boundaries. Sometimes a developer knows that a technology is flaky but it promises such a huge benefit that it’s worth the risk. The criteria for selecting a technology is what I’ll talk about today.
A number of factors come into play whenever evaluating any technology. It can be software or hardware, you still have to answer a set of questions about whether its a good idea. Let’s think about a few of the common ones.
  • Does it really solve the problem or do I just want to use it?
  • How long will it take to integrate and build from?
  • Does anyone at the company have any experience using it?
  • How much does it cost and are support agreements available?
  • What is the licensing scheme?
  • How big is the internet community?
  • What are the posts like in the support forum (if there is one)?
  • How long has it been available?
  • How does it impact the schedule?
This list is certainly not exhaustive nor in any particular order. It’s arguably short and other engineers may extend it out further too. It sounds odd, but I do carefully consider each of these questions before selecting a new library and hardware. Let’s go over each question.
Does it really solve the problem or do I just want to use it? What a dreadful question to ask? It is one that requires some introspection as to your own personal motives. Let’s say you are presented with a choice of TopLink and Hibernate and you haven’t worked with either but you’ve heard of both. Which one do you choose and why? Sometimes we inadvertently pick a technology that is going to help our resumes later. Face it, Hibernate is probably worth more to your career than TopLink. But what if TopLink is actually better for the scenario and can finish the project faster and more reliably?
This is a difficult challenge as you must remember that a new project is an opportunity to grow professionally and personally. There is also the ability to be forward thinking and realize that a given technology is growing and so more people are interested in learning it and want to work for places using it. Nonetheless, the first issue to resolve is whether the technology will really solve the problem. If the answer is no, then it is your obligation to move on in the selection process.
How long will it take to integrate and build from? You’ll spend some time trying to figure out how to get it to build in your application, packaging and deployment. Some technologies require one download after another to get all the dependencies and can be painful to get setup. Then figure out how to replicate it across all the developer’s desktops. You can put it in source control or someplace else, but the trick is putting it in a place that requires the least amount of individual developer effort to get it.
There is also a learning curve implied here. You will have to spend some time learning how to use it and write code to take advantage of it. Some technologies are poorly document and very complex. The early documentation days of Struts and Hibernate were only vaguely useful. They have evolved and become much easier, but back then the learning curve was steep.
Does anyone at the company have any experience using it? It is really helpful to hear the experiences of those that have used a technology. First, you get their experiences and good or bad, it is valuable. Second, you may learn something about your teammates and show respect by asking for their opinions. You only have to ask yourself if you like it when a developer asks you for your opinion on a design or implementation to be sure if this is a good idea.
How much does it cost and are support agreements available? Some libraries are open source but have commercial licensing requirements. In those cases you really need to consider the costs of a technology and sometimes you rule it out based on that alone. It is fairly common that some libraries require an OEM license, so you end up buying a license for every copy of your product. This is an annoying and time consuming process. The cost can sometimes be steep or completely inconsequential, but the time spent having to buy licenses and configure customers with those licenses is considerable. This may not be an issue if you send a person to install the product at a customer’s site or if you have a web service that you host.
Support agreements can be incredibly valuable if you use them. It happens often that people buy a support agreement and then never call. It’s a lot like a guy with OnStar whose lost but won’t ask for directions. He bought the service but he just won’t use it. Lots of companies buy service agreements for tens of thousands of dollars a year that they never use. Depending on the agreement you may have unlimited tech support and they can often answer a question a lot faster and more accurately than you can research it.
What is the licensing scheme? Some open source licenses are restrictive in how you may use and distribute the component. Some require you to open your source tree to the public. Some require you to only publish your modifications. Finally, some let you do whatever you want with no restrictions.
I believe that this is the most important question to answer. It is not worth even prototyping code if the license agreement is not compatible product’s sales model. It happens often that a developer picks library with the wrong kind of license and several months later he spends weeks removing the code because he can’t sell the product because of the license.
How big is the internet community? The size of the internet community tells you how popular it really is. In particular, pay attention to the number of blogs talking about it and whether it is positive. Look for people talking about their experiences rather than tutorials. Experiences tell you what it is like to use the technology six months or a year from now, how long it takes to learn and the various gotchas. The bigger the community, the more likely it has been successfully used in other applications. If they could do it successfully then you can too.
There is the risk of zealots. These are the guys that couldn’t imagine using anything else ever. I am careful to take a zealots opinion as a grain of salt. I’ve run into too many zealots that want to use fringe languages, strange protocols and really odd design patterns to solve very common problems. I become especially paranoid of these guys when they are involved in language development as they will recommend that your Java or PHP web application be rewritten in something odd and complicated, like Ada.
What are the posts like in the support forum (if there is one)? Forums can be extremely valuable, except when they are accused of censoring. The value is that you see the kinds of problems that other adopters are experiencing and how they solved them. The common problems are often easy to see from titles alone. The difficulties people are having can also be figured out by the number of readers for a given post.
No forum, or a censored forum, leaves you with very few places to turn for help. Even the simplest library has bugs and has corners that are poorly documented so a developer cannot assume that he will never need help. No forum means very little help.
How long has it been available? This one is a little tricky. Some new technologies are just so incredibly valuable that their age is almost irrelevant. Take Adobe AIR and Google Gears as examples of amazing new technologies that only came on the scene a short time ago.
Consider that you are looking at two different Javascript libraries where one is two years old and the other is only three months. The three month old library may not be as well tested, may not have the community, but more importantly, it hasn’t proven that the developers supporting it are going to be there for the long haul. Just imagine getting into a year long development cycle and finding out that the OSS developers for your Javascript layer have decided to move on and now your stuck with an unsupported third-party Javascript library.
How does it impact the schedule? Some will argue that this shouldn’t factor into the decision making process at all. However, we are expected to produce a lot of code usually at an aggressive pace. Scheduling becomes a very important factor because we are expected to continue producing code and product, not researching something genuinely interesting.
The schedule impact can be broken down in several ways:
  • Time to learn
  • Time to prototype (optional and recommended)
  • Time to implement
  • Time to learn how to debug
  • Time to integrate into the build system
  • Time to deploy
  • Time to test
You then compare the schedule impacts of using a different, equally applicable, technology. Let’s say you have experience in Struts and you want to switch to Tapestry because you’ve heard so many good things. You figure that the Struts implementation may take three weeks to integrate, build, and deploy, but all your reading says the Tapestry implementation will take only a week, maybe two at the most. The difference is the learning curve. Will it take a week or two to figure out the right implementation? How does that affect the schedule now?
Using a new technology requires a lot of schedule padding. The bigger the framework, the more padding. It may work really well and pull in your schedule initially but an unforeseen glitch, like lack of experience with the technology, in your design may use the technology in an odd way and ultimately delay your release by a month or more.
The other scheduling issue, especially when presenting the plan to a project manager, is if the tried-and-true way has nearly the same schedule as the new technology way. Its very hard to argue the merits of a new technology when an old technology takes just as long to implement.
We have looked at some criteria for choosing technologies. To me, the only criterion that is an actual gating condition deals with the licensing terms. The others need to be balanced against each other to see if the overall picture of the technology’s impact is positive enough to warrant the various risks. If all things are equal, then you are left with one last item to consider: your reputation.
Your reputation within an organization is incredibly valuable. Every time you make a great choice your reputation increases. The better your reputation, the better assignments later and a greater likelihood of promotion, pay raises and leadership opportunities. So when choosing a technology, be sure that it’s something you are very sure will work, as success opens doors.

Refuctoring: Winning the Respect of Your Peers

In "No, Be a Jerk", Justin talks about the importance of giving honest criticism of other developer's code. I agree that providing constructive feedback is important. My designs and code improves when there is discussion about how and why a component was written in a particular way. Talking about a problem and giving feedback is a great way to create innovative and elegant methods for solving problems through code. Uninvited refactoring is far more risky.
Just because you are working in someone's code does not mean that you have the right, the wisdom nor the back-story to make sweeping changes that may come with refactoring. A wise way to refactor is to talk to the responsible developer first and verify that your changes will improve the code base, meet schedule requirements and be an appropriate use of your time.
Let's say your have to make a bug fix for a NullPointerException in another developer's code and you see an inefficient sorting algorithm outside of the code affected by your bug fix. You could make the bug fix and refactor the code all in one commit. It seems like a good idea.
There are plenty of reasons not to make any changes beyond your bug fix. First, the code you want to refactor probably works and introducing changes takes that proven code and throws it back into doubt. Just because the refactored code works from JUnit does not mean that it will work from the UI or any other client. Refactoring can add new bugs to previously working code and lengthen the development schedule.
Second, the original code may not be as efficient as it could be, but then again it may not matter. There is a code that marginal or even major performance improvements are irrelevant. A common example is a sorting routine that gets called once in awhile and runs for only a couple of seconds. Shaving even 50% off that time may be interesting but not important since the routine doesn't get called often enough to make a big difference.
Third, the code may have been written that way to solve another specific problem. There are times when a somewhat slow algorithm is necessary because you don't have enough other resources to make it perform better. For example, you may have a memory constraint that doesn't allow you to use a higher performance algorithm. Refactoring this code without the constraint may cause a regression.
Finally, changing code out from under the owning developer may make him pretty annoyed. Small changes may be fine, however sweeping changes without consultation sends a deeply disrespectful message. You still have to work with the developer and maybe face him everyday.
Many of these beliefs come from previous jobs where people went in to working code and refactored. The best case was that the developer didn’t care that his work was redone. The typical case was that the owning developer was pretty ticked off and went to his friends and complained about the situation. The worst case, and one that happens a lot, is that working code gets refuctored with new hidden bugs and delays the delivery date.
I’ve been involved in a fair amount of team scheduling and oversight of late. The simple fact is that there are features to deliver and milestones to hit. Working code is generally considered to be good enough until a real problem comes along. This sounds like a cop-out, but the reality is that suboptimal code does not become a problem until the application is no longer within the constraints in the requirements specification or a customer complains. At that point it gets on the schedule and then it can be fixed in a thorough and thoughtful way.
Don’t get me wrong, I agree that most projects have some amount of bad code and there has to be a way to communicate that fact and fix it. Bad code is not restricted to poorly performing code either. I’ve seen plenty of functions that were pages long that needed to be broken up. Code with cut-and-pasted functions being repeated across classes with a common derivation are incredible candidates for refactoring. The issue is making sure that you are able to communicate a set of changes to the responsible developer and give him the opportunity to defend his choices.
It's great to suggest changes and to volunteer to do them yourself. It's good to be honest and to try to improve other developer's code in a constructive way. The important part is to talk to that developer before making major changes in order to understand why code was written in a particular way. It saves time, teaches and shows respect for your colleague's efforts.