I once rewrote an entire program in another language. Why, you ask? At the time, I thought the software would improve by virtue of be written in what I considered to be the better language choice. Perhaps my naive assumption stemmed from the hope that customers actually care about such decisions when interacting with my software. I never had the opportunity to become that customer before realizing that hardly anyone using a system ever stops to think about the design decisions that have made their way in. The only ones who truly pause and think "hey, wouldn't this be spectacular if we could just rewrite this in a language that runs on many platforms instead of maintaining many code paths" are us — the ones who write the software to begin with.
Showing posts with label refactoring. Show all posts
Showing posts with label refactoring. Show all posts
Wednesday, October 10, 2012
Monday, October 3, 2011
Time To Refactor
Refactoring existing code makes better software. Martin Fowler has championed this concept and as a result, developers look at refactoring code as an essential part of the process — not something to do on slow days. Of course, idealizing over code design is one thing — making it a reality is another. Unfortunately, refactoring doesn't happen for one reason or another — usually there isn't enough time.
But what about the programmers that have to stare this code in the face — day in and day out, watching unruliness assume control? They're the ones who see the problematic consequences of letting ugly code grow and metastasize into other subsystems. Programmers probably don't decide there is no time to for refactoring.
If there is no time to refactor code, when will it get done, if ever? Understandably, features and enhancements are expected. Expected yesterday. Maybe there is a way for software developers to convince stakeholders that refactoring is the only option left. Maybe we can treat, somehow, refactored code as a feature?
Code gains weight fast
Code gains weight at an alarming rate. You might start off your hacking session with a small set of classes, maybe a couple utility functions. It takes only a couple hours for this lightweight setup to transform itself into a bloated plate of spaghetti code. Not because you don't know how to write elegant code, but because others are depending on you — it just needs to work. If we wanted beautiful code the first time around, we're in the wrong business. Refactoring is about improving existing code, not code that has yet to be written.
As programmers, we idealize solutions — before sitting down and typing it into the editor, we've at least, if only briefly, conceptualized a few alternative approaches to tackling the problem. This isn't considered big, upfront design — it's more of a personal game plan to help spring us into action. But, since this is only a quick mental note — not using real code and a real editor and not running real tests — chances are the some aspect of our plan is wrong.
The trouble is, we don't know that some aspect of our ideal implementation is invalid until it's concretely implemented and executed. Sometimes our code doesn't even reach the point of execution before we've realized it doesn't fit. Sometimes all it takes is a glance at the interfaces you're working with or the documentation of another component dependency to realize that there is a sudden change in plan.
This sudden realization means that the nice, natural flow that we had envisioned, the one that motivated us to get going in the first place, has been scrapped, ups the urgency of the situation. Maybe the entire metal workflow isn't thrown out, but the calm confidence we had slowly dissipates. We're probably not following a waterfall approach — so we need to adapt quickly — pound out something that'll work. Otherwise, the forward motion of the entire project is jeopardized.
Fixes to sudden disruptions aren't difficult to implement, but they're not the most elegant or efficient solutions. And so the code gains weight. It works, but it's become heavier — in terms of raw size and in logical baggage — all within a few hours.
Features are released on time
Software projects have a brigade of developers, all with the attitude of making sure things get shipped when expected. Even if that means not setting aside some refactoring time. This process, this seemingly endless cycle of pounding out lines of code, is very rewarding. Getting stuff done on time is a recipe for success in any software project as far as I'm concerned.
This is the habitual part of it for the programmers — who wouldn't want repeated success by continuously pleasing customers and other stakeholders by shipping early? Don't fix what isn't broken, right?
And so life goes one — each cycle of the development process yielding a new and enhanced version of the software that exceeds customer expectations. It's hard to change a good thing while it's good — making decisions to refactor code can seem unjustified. Is there another way to squeeze in some code improvements that don't necessarily please the client directly?
Well, small incremental improvements can typically be tucked-into sections of the software system during the development process. These are low-risk, low-effort improvements that don't have an immediate impact on code comprehensibility but instead have a concerted long-term impact. The trick is — making these small incremental refactorings — is really only beneficial if they're a habitual task of each and every programmer working on the project — cumulative change for the better. But this can be overridden, mentally, by that other little habit — satisfying the customer by shipping on time.
Forcing the issue
Two competing ideologies vetted against one another — the ship on time versus the refactor messy code — lead to one of two places. Perhaps the worst thing that can happen is programmers get caught up in cleaning up code and as a result, deadlines for requested features tend to slip. What we have in this scenario is some nice looking code and a frustrated group of stakeholders. The product is better off now that the mess has been tidied — paving the way for future ingenuity — but how do you explain that to non-programmers?
The second outcome, and perhaps a good selling point for investing time in refactoring code, is a garbled mess that can't be updated with new features or enhancements to existing features. There is an illusion that this will never happen because it takes a while to happen. A misconception of those involved in software projects who don't write any code is that code is an immutable thing — once it's written, it's there and it should just work. Ask any software developer and they'll tell you that any body of code is a living organism — one that must be fed and cared for.
So, forcing the need to refactor. The best way to explain it to those involved in the project but do not understand the concept of refactoring code is to present it as a feature. Or, sometimes even more effective, present it as a blocker for new, potentially interesting features. This second approach takes some inventiveness, but is ultimately the most effective way to communicate the state of the code base to non programmers. Think features they'd like to see and what would stop them from happening in terms of the current state of the code.
The reason this approach — let's call it proactive refactoring for features — works so well as a communication tool is that you're taking a deficiency in the fundamental code structure and presenting it in business objective. Rather than trying to introduce the philosophy of refactoring code — because I can tell you right now they're not interested — you're taking a valid business concern and presenting it in a cohesive way.
One final suggestion on proactive refactoring for features — back your claims up with evidence. Not a written words, but a quick little prototype that'll make very obvious the problem at hand. Nothing says urgency like proof that a potential money making feature might not work in our product down the road.
But what about the programmers that have to stare this code in the face — day in and day out, watching unruliness assume control? They're the ones who see the problematic consequences of letting ugly code grow and metastasize into other subsystems. Programmers probably don't decide there is no time to for refactoring.
If there is no time to refactor code, when will it get done, if ever? Understandably, features and enhancements are expected. Expected yesterday. Maybe there is a way for software developers to convince stakeholders that refactoring is the only option left. Maybe we can treat, somehow, refactored code as a feature?
Code gains weight fast
Code gains weight at an alarming rate. You might start off your hacking session with a small set of classes, maybe a couple utility functions. It takes only a couple hours for this lightweight setup to transform itself into a bloated plate of spaghetti code. Not because you don't know how to write elegant code, but because others are depending on you — it just needs to work. If we wanted beautiful code the first time around, we're in the wrong business. Refactoring is about improving existing code, not code that has yet to be written.
As programmers, we idealize solutions — before sitting down and typing it into the editor, we've at least, if only briefly, conceptualized a few alternative approaches to tackling the problem. This isn't considered big, upfront design — it's more of a personal game plan to help spring us into action. But, since this is only a quick mental note — not using real code and a real editor and not running real tests — chances are the some aspect of our plan is wrong.
The trouble is, we don't know that some aspect of our ideal implementation is invalid until it's concretely implemented and executed. Sometimes our code doesn't even reach the point of execution before we've realized it doesn't fit. Sometimes all it takes is a glance at the interfaces you're working with or the documentation of another component dependency to realize that there is a sudden change in plan.
This sudden realization means that the nice, natural flow that we had envisioned, the one that motivated us to get going in the first place, has been scrapped, ups the urgency of the situation. Maybe the entire metal workflow isn't thrown out, but the calm confidence we had slowly dissipates. We're probably not following a waterfall approach — so we need to adapt quickly — pound out something that'll work. Otherwise, the forward motion of the entire project is jeopardized.
Fixes to sudden disruptions aren't difficult to implement, but they're not the most elegant or efficient solutions. And so the code gains weight. It works, but it's become heavier — in terms of raw size and in logical baggage — all within a few hours.
Features are released on time
Software projects have a brigade of developers, all with the attitude of making sure things get shipped when expected. Even if that means not setting aside some refactoring time. This process, this seemingly endless cycle of pounding out lines of code, is very rewarding. Getting stuff done on time is a recipe for success in any software project as far as I'm concerned.
This is the habitual part of it for the programmers — who wouldn't want repeated success by continuously pleasing customers and other stakeholders by shipping early? Don't fix what isn't broken, right?
And so life goes one — each cycle of the development process yielding a new and enhanced version of the software that exceeds customer expectations. It's hard to change a good thing while it's good — making decisions to refactor code can seem unjustified. Is there another way to squeeze in some code improvements that don't necessarily please the client directly?
Well, small incremental improvements can typically be tucked-into sections of the software system during the development process. These are low-risk, low-effort improvements that don't have an immediate impact on code comprehensibility but instead have a concerted long-term impact. The trick is — making these small incremental refactorings — is really only beneficial if they're a habitual task of each and every programmer working on the project — cumulative change for the better. But this can be overridden, mentally, by that other little habit — satisfying the customer by shipping on time.
Forcing the issue
Two competing ideologies vetted against one another — the ship on time versus the refactor messy code — lead to one of two places. Perhaps the worst thing that can happen is programmers get caught up in cleaning up code and as a result, deadlines for requested features tend to slip. What we have in this scenario is some nice looking code and a frustrated group of stakeholders. The product is better off now that the mess has been tidied — paving the way for future ingenuity — but how do you explain that to non-programmers?
The second outcome, and perhaps a good selling point for investing time in refactoring code, is a garbled mess that can't be updated with new features or enhancements to existing features. There is an illusion that this will never happen because it takes a while to happen. A misconception of those involved in software projects who don't write any code is that code is an immutable thing — once it's written, it's there and it should just work. Ask any software developer and they'll tell you that any body of code is a living organism — one that must be fed and cared for.
So, forcing the need to refactor. The best way to explain it to those involved in the project but do not understand the concept of refactoring code is to present it as a feature. Or, sometimes even more effective, present it as a blocker for new, potentially interesting features. This second approach takes some inventiveness, but is ultimately the most effective way to communicate the state of the code base to non programmers. Think features they'd like to see and what would stop them from happening in terms of the current state of the code.
The reason this approach — let's call it proactive refactoring for features — works so well as a communication tool is that you're taking a deficiency in the fundamental code structure and presenting it in business objective. Rather than trying to introduce the philosophy of refactoring code — because I can tell you right now they're not interested — you're taking a valid business concern and presenting it in a cohesive way.
One final suggestion on proactive refactoring for features — back your claims up with evidence. Not a written words, but a quick little prototype that'll make very obvious the problem at hand. Nothing says urgency like proof that a potential money making feature might not work in our product down the road.
Thursday, April 8, 2010
The Face Of Bad Code
Lets face it, we've all written bad code at one point or another. If we hadn't, we probably would never release any functional software. Remember, code that isn't ideal doesn't equate to code that doesn't run and help someone else accomplish some task. Code can always be re-factored, and, it should be re-factored.
I often find myself testing my own software from and end user perspective and thinking about the code that is running when I perform certain actions. I think "well, it works, but just barely". I have to force myself to think "well, it works, and that is all the user cares about; it can be re-factored later".
Don't be tempted to re-factor before you get something functional into the hands of the end users. Make notes on what doesn't work well and fix it in conjunction with the user-provided feedback. If you don't release, you don't get the feedback. Only you as the developer know what needs to be re-factored, only the end user knows how well your software solves their problem.
I often find myself testing my own software from and end user perspective and thinking about the code that is running when I perform certain actions. I think "well, it works, but just barely". I have to force myself to think "well, it works, and that is all the user cares about; it can be re-factored later".
Don't be tempted to re-factor before you get something functional into the hands of the end users. Make notes on what doesn't work well and fix it in conjunction with the user-provided feedback. If you don't release, you don't get the feedback. Only you as the developer know what needs to be re-factored, only the end user knows how well your software solves their problem.
Monday, March 1, 2010
Math And Code Design
I was reading about the debate on math education reform in Scientific American and the argument for giving kids more context in which to apply theory is similar to applying the re-factoring approach to software development. Trying to design perfect software the first time around is an exercise in futility. Better to quickly bang something out that works, then go back and re-factor the code so that it is better designed. This way, you have a real-world context as well as real-world constraints in which to design your existing code. Maybe this approach isn't suited well for learning math concepts but it certainly couldn't hurt in introductory programming classes.
Labels:
code
,
design
,
development
,
math
,
refactoring
Subscribe to:
Posts
(
Atom
)