While talking through some upcoming sprint candidates, I pushed a BA for more information because I wanted to 'get the code right first time'. The BA's response to this request was that he deemed it 'un-agile'.
I found that quite interesting and I wanted to talk about why coding things correctly first time has value and is agile, and that it's also not subject to the 'just enough' / 'just barely good enough' mantra that agile promotes.
Getting the code right first time is a statement borne out of numerous re-writes and refactors due to code having not been right first time. Did it work? Sure. Was it good enough? No. But why was that, and why is it so critical?
The cost of refactoring is obviously high. Writing something that works and then rewriting it again at some point incurs obvious costs in man hours, however it also costs something much more than that. A codebases 'quality' is such a fragile ecosystem that it takes very little for it to be broken. Bad code impinges on this ecosystem so much that in The Pragmatic Programmer it's posited that a bad piece of code is like a broken window in a building: it's an invitation to break more windows, an invitation to write more bad code. Once bad code is introduced, it can spread like wildfire - copied by those who don't understand it and turning hastily into an anti-pattern. Sealing these windows up - fixing bad code - is critical for the continued quality of the codebase. Taking a beat and writing something right first time is the first - and most critical - step towards this ethereal chalice we call quality.
Just good enough may be alright in a conceptual sense, however in a practical sense we must raise the bar of what good enough really is. Good enough not only adheres to the agreed patterns and practices, it refines and improves them. It drives comment amongst developers and serves to benefit the overall quality of the codebase, and ultimately the quality of the application. These are things we all try to do, but only through an appropriate amount of thought do we draw the right conclusions. Making sure your code adheres to the principles of SOLID is a good start. A method should do one thing and one thing only, and it should do it bloody well. Business logic does not belong in the presentation layer, and presentation logic does not belong in the business logic layer. Is the domain simply a representation of state, modified by external code, or does the domain manipulate itself? Making sure everyone is on the same page, but also making sure everyone is striving for something a bit better that gives value to the rest of the team is critical.
So is it un-agile to get the code right first time? I don't think so. The inherent benefits may simply be lost on those who aren't working on the code every day. Getting it right first time is not doing too much work, it is not doing more than the bare minimum. This is because our definition of the bare minimum is different to a few lines on a story card. The bare minimum for a developer involves a high standard. An eye on the future. Thinking about others in the team and how they will feel when they see your code. But most of all it's about taking pride in your work and mending those broken windows every time you see them.
To close off this post I will ask you one question: if you're working on a closed source system - as a lot of us in the .Net world do - would you be proud if it were open sourced, or would you want to go back and fix up a few things first?
Well it's time for an update!
I've been hacking about a lot on Ruby and Rails recently and it's becoming ever more powerful with each release.
The reason I've taken so long to 'convert' from python and Django is the built-in admin functionality Django provides, however I'll hold my hand up to my own naivety towards the rails community because there's plenty of amazing gems to offer registration and administration now.
The first of which is rails admin.
Installation instructions can be found here and it's a doddle to get up and running
I'll try to keep updating this with added bits. Next time, how to allow image uploads with rails_admin
I was receiving the error The object cannot be deleted because it was not found in the ObjectStateManager. with the following code:
Oddly, I managed to fix it with the following code:
It seems that FirstOrDefault behaves differently to Where().FirstOrDefault() within Linq-to-SQL.
Weird one, huh?
Hit a bit of an issue at work today. Our models were decorated with the standard DataAnnotations attributes such as Required and RegEx-based ones, but couldn't get them to fire.
After some trawling I came across a page with the answer.
Calling this once the form is on the page, i.e. if invoked via the Ajax helper passing in the method to the OnSuccess AJaxOption, e.g.
I went to Udi Dahan's talk on NServiceBus hidden gems last week.
It was a very interesting talk with quite a few useful bits and pieces which are on my notepad at work. I'll try and write them up this week...
I visited the London .Net user group last week and saw a brief intro to Coypu.
It looks pretty interesting though its tests currently only all pass with the Firefox driver. It's a wrapper for Selenium and WatIn and has a more fluid, user-friendly API for interacting with web projects.
I've found myself currently struggling to unit test the front end of the new application at work.
The main issue has been the dynamic nature of the controls we're showing. In order for Selenium to work, each control on the page must have a unique ID/name.
Easy enough, right?
Well, because we have a set of data capture controls of an unknown length - some of which may exist many times on a single page - giving them meaningful identifiers in a consistent way is key for the testers' Selenium tests to work the same way every time.
The way we fixed it was to create a hierarchy within the domain, for example:
And then from the Unity-drivent session-held Page holder, ask the page to update its control ID and all its children's control IDs. They then do them same, ad infinitum. Because each uses its own ID with that of its predecessors, the control IDs are unique to the object tree but reproduce themselves the same every time.
sudo /etc/init.d/apache2 restartand
sudo /etc/init.d/nginx restart