Sometimes while I am writing code I like to pretend that every chunk of non-trivial code is my enemy. In order for me to be successful in my task, I must not get surrounded by too many of my enemies, or all will be lost. Okay, so I don’t actually pretend that, but that would be pretty sweet, wouldn’t it? Well, if by “sweet” I meant “nerdy”, then yes, it would be “sweet”. Anyways, I do however try to hide as much code as possible so that I can see the intent of my code, rather than the actual implementation details.
This is an approach which goes right along with the declarative programming fad the is currently going around, where we want to be able to write less ceremony and more substance.
For example, I don’t want to have to filter and sort a list like this:
var result = new List<Person>(); foreach (Person person in people) { if ((person.Age > 40 && person.Weight > 180) || (person.Age > 20 && person.Weight > 200)) { result.Add(person); } } result.Sort((p, q) => { int lastResult = p.LastName.CompareTo(q.LastName); if (lastResult != 0) return lastResult; return p.FirstName.CompareTo(q.FirstName); });
I just want to be able to tell the list to filter itself, and let the compiler sort the rest out:
var result = people.Where(p => p.Age > 40 && p.Weight > 180) .Union(people.Where(p => p.Age > 20 && p.Weight > 200)) .OrderBy(p => p.LastName) .ThenBy(p => p.FirstName);
Works very well, but in reality, the compiler really isn’t the one deciding what to do here. It just so happens that someone wrote a library to abstract away from me the ceremony of looping through the list and doing each and every comparison. So why wouldn’t you want to write your own code that way? What do you think is easier to read, this:
Person[] people = PersonRepository.GetPeople().ToArray(); Person oldestPerson = people[0]; foreach (Person person in people) { if (person.Age > oldestPerson.Age) { oldestPerson = person; } } Person heaviestPerson = people[0]; foreach (Person person in people) { if (person.Weight > heaviestPerson.Weight) { heaviestPerson = person; } } if (oldestPerson == heaviestPerson) { oldestPerson.CancelInsurance(); }
Or this?
Person[] people = PersonRepository.GetPeople().ToArray(); Person heaviestPerson = GetHeaviestPerson(people); Person oldestPerson = GetOldestPerson(people); if (oldestPerson == heaviestPerson) { oldestPerson.CancelInsurance(); }
To me I think that the answer is pretty obvious. (And yes, I could have made it cleaner with Linq, but I’m trying to make a point!) Although I’m not sure I agree with the logic of the code. Seems pretty crappy. 🙂 Yet many developers don’t do this. Instead, they optimize for themselves in the current point in time. As long as the complexity does not overwhelm their brain in the moment they are writing their code, they don’t try to hide anything or take the time to abstract. The problem is that your brain at the moment of writing the code is primed, pumped, and immersed in the logic of your code. In other words, your brain one week from now will not be able to full grasp the logic of the code you are looking at until you have walked through it and immersed yourself in it. So we need to write code for your future self.
I know that some people will probably get upset about me telling developers to hide code, but I honestly think that very little bad could come out of following this device. I’ve had people in the past that have criticized my code because they had to step through so many methods in order to get to where they wanted to be, but I’m not sure why they couldn’t have used the breakpoint or just read the code. I guess they are used to code being so complex that they can’t just read through it. (That’s right…I rock hard! Ha.)
I think the problem of not being able to see "everything at once" is really only applicable in very simple situations. What the human brain has problems with is breaking a problem down into pieces, not in being able to see it. I can put a million things in front of you and your brain will be able to see each one, but will your brain be able to pick apart and understand each piece? Absolutely not. So come on, just abstract it already.
Loved the article? Hated it? Didn’t even read it?
We’d love to hear from you.
Putting logic into separate methods isn’t hiding code, it’s normal coding practice. Isn’t it?
Extension methods are a pretty good way of exploiting linq method chaining while avoiding it ending up looking like the bastard son of a 2001 data access layer.
This is an attempt to make hairy reflection queries in metaprogramming a little more bearable.
[quote]
return typeof(TModel).GetInterfaceProperties()
.Union(typeof(TModel).PropertiesDerivedFrom<IDto>())
.Union(typeof(TModel).PropertiesParameterisedBy<IDto>())
.Union(typeof(TModel).PropertiesWithAttribute<DontStoreAttribute>())
.Union(typeof(TModel).PropertiesWithAttribute<OptionAttribute>())
.Select(p => p.Name);
[/quote]
I’d kill for a library levelling this sort of stuff into a consistent set of extensions. Designing it would be damn hard though.
@Rik:
You’d think this would be a simple practice that all devs followed, but that’s not always the case.
I’ve actually worked with other devs that did backwards refactoring on code I wrote. Turning nice, simple short methods into long, hard to read code chunks because they liked seeing all the code in one place (obviously they didn’t care that it was impossible to test either). Since they were the client, all I could do was try my best to explain why smaller methods are better. And at the end of the day, they were the ones who had to maintain the software.
@John Thanks! I was getting ready to write a comment that would have looked exactly like yours. You would think that this would be common practice, but it really isn’t in many systems that I have seen.
[quote]Turning nice, simple short methods into long, hard to read code chunks because they liked seeing all the code in one place[/quote]
I have seen this done at a few places, it’s a pretty common thing to do when people live in the debugger and want to be able to easily check as much state as possible. Drives me up the wall, and out of the door.
It is not so much ‘hiding’ the implementation or creating an abstraction. It is more so organizing and explicitily stating what is happening.
Amen 🙂
I keep getting spam from this post. Can you please fix the spam or remove me from the notify list?
Thanks,
Rik