I used to be a perfectionist when it came to code, but now I’m a firm believer in shipping code that works, regardless if its perfect. Then, only if my assumptions are proved correct I return to the code to refactor it. Otherwise I dispose of it. This is how I run my software businesses (apps, software as a service, etc). I bootstrap all of my products and doing the following has allowed me to bootstrap faster than most competition. The rule is:
Ship code that works, regardless if its perfect.
Early I my career if the code in question didn’t have 80% minimum unit test coverage, didn’t conform to all the proper design patterns and the indentation/variable naming was incorrect I wouldn’t let it past my desk. Not any more.
I ship legacy code. I ship ugly code. I ship stuff I’m embarrassed of. I ship stuff that I don’t want you to ever see. Its that bad.
Why?
Because code that ships confirms assumptions and pays the bills. Perfect code that sits in source control doesn’t do anything.
But, if the code is ugly/legacy its going to cause problems, might have bugs, and can cost more later on to fix. I need to get it right the first time otherwise it will never get done right.
I agree. That is a possibility. It is a known fact that fixing a bug in development is exponentially cheaper than fixing it after its shipped. I agree with that 100%. I do think you should write clean code that is well designed, at the proper time.
Well, you’re telling me to NOT write clean code but sometimes you say I should. When should I write clean code?
When you’re building on top of a known positive assumption that has proven itself.
Huh? What? What do you mean? Let me ask it differently, when should I hack code together?
When launching a new product or new feature. During these times I write the code that gets the feature done as soon as humanly possible so I can ship my products. I want it done quickly so I can test my assumptions against the market (users/etc). If my assumptions prove correct (users use the feature and like it/they made a purchase or upgrade/etc) then I know my assumptions are correct and at that time I can refactor into a proper design. However, if my assumption proves false (user does not like the feature/it does not convert/etc) the cost of service performed (development of the code) is substantially less than if the code was architected perfectly.
This is how you ship your product faster. Stop being a perfectionist. Get it working. Ship it. Test your assumptions. Refactor it. Rinse. Wash. Repeat.
In some circles this is recognized as part of the Lean Methodology.
Caveats
If the code to be written is small enough in nature that hacking it together vs writing it properly is the same then I will choose to do it properly. Also, if the code is so complex that it needs proper design then sometimes there is no way around it. Sometimes you need a huge suite of tests to makes sure that your feature works the way your expect it to. Sometimes it needs to be architected properly and thats Ok too. But if you don’t have to do it, then don’t until your assumptions are proven.
Additionally, there are times when you work for a company and once the code is shipped you’ll never get to touch it again because of the culture of the development team and product releases (I’ve worked at many of these). This may mean that once a feature/product is shipped you never see it again because you (or the team) is working on a new project already. If you work at a company like this, you need to design properly up front because when you come back to update/fix the app in 6 months you don’t want to walk into a huge mess of legacy code.
Cindy Potvin says
So true! Sometime you need to ignore the perfect architectural solution to have the time to finish and ship. Software that is not shipped is useless.