April 2006 Archives
...Omni Group Ad.
Although they missed to show the cursing, screaming & yelling at the computer which happens far more often then the end-zone-dance :-)
Hugh on doing the best you can.
I don't mind people giving us feedback on our products. I don't mind people making suggestions on how the software could be improved. I don't mind people pointing out glaring omissions, substantial flaws, bugs & crashes. I know our software has bugs, can & should be improved substantially. As Dave Winer puts it: "We make shitty software and we know it".
In fact, we rely on the feedback to provide a better product.
What I mind is the way in which feedback is provided - and 37signals post showed some of the ways. What I mind is the general attitude of somebody not involved with the development of some piece of software presuming to know that some things are trivial & absurd.
I don't talk about diplomacy - I talk about courtesy. That's something we should have learned from mom and dad back when we were kids. Courtesy doesn't come in the way of pointing flaws & bugs precisely. In fact, courtesy requires us to point out flaws & bugs precisely. Courtesy also doesn't hinder us from cursing at software developers, screaming, yelling, wonder about their stupidity or using a broad selection of four-letter words. As long as we're doing it while in a room all by ourself.
Courtesy is about treating others with the respect they deserve. Because we want to be treated the same.
Useless, absurd, must, need, appalled, just, infuriating, essential, etc.
That's what I'm hearing everyday.
As a developer, I face complex problems everyday (or should I say complex problems are upon me everyday? :-). I may come up with a rather lengthy serial blurb of code with a couple of conditions & loops. This blurb may neither be an object-oriented nor a clean, maintainable piece of code - yet. The code may look easy-to-understand and simple to me now because I'm still fully engaged in the problem and its solution. There are three key factors which contribute to its complexity:
- Length of methods / scoped code blocks
- Number of conditionals
- Number of loops
Reducing this undesirable complexity is straightfoward: Ruthlessly reducing duplication. During this process, I will most likely introduce new methods and new classes. This sure makes the system itself more complex, too. However this is desirable complexity - complexity which can be easily dealt with in future revisions of the code. Because I reduced duplication and decoupled the different components of my solution.
Or, to rephrase it, reducing unmaintainable complexity with managable & maintainable complexity.
So for any reasonably powerful feature or piece of functionality added to a system, the code won't be simple. It will add complexity to the system. But doing it right will ensure that the system can still be dealt with in the future.
...von King Kahn. Hut ab.
Here's an excellent post by James Shore: Quality With a Name.
If you haven't time to read it all, make sure to read the section "Principles in Practice", where James discusses private instance variables and nails the issue right on the head.
I applaud the courage of the Office 12 UI team to take the risk and introduce a new UI (the "Ribbon" being the most prominent feature of the new UI) to deal with making Office more accessible, discoverable and in the very end, usable.
This is great stuff and worth looking into in great detail. Here are some great resources on the new Office 12 UI:
Es geht um viel, es geht um die zweite deutsche Einheit: um die zwischen Alt- und Neubürgern, also zwischen Bürgern deutscher und ausländischer Herkunft.
How about rephrasing
void foo() {
if (nothingToDo) { return; }
// Implement typical behaviour of foo()
}not like
void foo() {
if (!nothingToDo()) {
// Implement typical behaviour of foo()
}
}but like
void foo() {
if (someThingToDo()) {
// Implement typical behaviour of foo()
}
}The latter version avoids the double negative (thus concentrating on the standard case and not the exception), and I consider it quite readable in practice, e.g. if (resourceAvailable()) doSomeThing(). However, this will only be a viable alternative to the guard clause if foo() is very short. If foo() get's so long that using the guard clause seems appropriate because the function will be more readable, maybe it's time to take a long hard look at foo() to search for refactoring opportunities. Avoiding guard clauses may help in detecting functions which got out of control in terms of length & complexity - because there's an awful lot of "intended code" in the function.
In the end, it boils down to personal preferences. Guard clauses are probably fine as long as the length & complexity of the function is monitored closely.
void foo(boolean condition)
{
int returnValue = calculateSomeValue();
if (condition)
returnValue = calculateSomeOtherValue();
return returnValue;
}
Two considerations:
First, if calculateSomeValue() is O(1) or even O(n), I would still use the proposed single-exit/no-else variation. Truth to be told, I don't even care if calculateSomeValue() is O(n*n) - I would go for the simple solution anyway. If, and only if, performance analysis shows that foo() is a system bottleneck, I would change it.
Second, if calculateSomeValue() has some undesired side-effects and thus should only be called if condition is indeed true. What's "undesired side-effect" in this context? If the undesired side-effect is performance / resource-related (e.g. calculateSomeValue() goes out to fetch some data from a database or from a web-service), then it's just a variation of the O(1)/O(n)/O(n*n) discussion above. I would still go for my single-exit approach and worry about performance later. On the other hand, if "undesired side-effect" means calculateSomeValue() does some changes to the systems state in addition to, well, calculating some value, then my suggestion is to check if this wouldn't be great opportunity to improve the design & implementation of calculateSomeValue(). If that's not possible, e.g. when working in a legacy-code environment, then I would go for the two-exits approach.