Programming Psychology - Return home early
Posted on 25/4/08 by Felix Geisendörfer
Hey folks,
this is an experimental post on the psychology of programming. As of lately I have become very interested in the thought processes that cause us to write certain code. Because I believe understanding the patterns in your own thinking will by far make the biggest impact on how good you will get as a programmer. Forget design patterns, forget unit testing, forget all those functions you know. Important is to question why they exist and how they could be improved. I'm not saying you cannot be a good programmer if you do not care about this. But I am saying you will most likely never exceed the skills of all the other programmers out there. You will more or less write the same code everybody else does.
In the scope of this post I will try to explain a very simple thought pattern that I am calling "return home early" that evolved out of me analyzing my coding habits. The simplest way for you to follow the thought process is to have a look at the following bad code:
$this->Post->set('id', $id);
if ($this->Post->exists()) {
$post = $this->Post->read();
if (!$this->RequestHandler->isGet()) {
if ($this->Post->validates()) {
if ($this->Post->save($this->data['Post'])) {
$this->Message->add('Post was saved successfully.', 'ok');
} else {
$this->Message->add('A db problem permitted your data from being saved', 'error');
}
} else {
$this->Message->add('Post was saved successfully.', 'ok');
}
Assert::notEmpty($result);
} else {
$this->data = $post;
}
} else {
$this->render('404');
}
}
What you see is a typical Post::edit action like the one used on this blog (in fact I derived it from it). I tried to cripple the code so badly that you can tell what is wrong with it right away:
There are way too many levels of nesting for something that should be dead simple.
But yet, most projects that I have been involved with had code like this in them. This is not because most programmers are stupid, I think this is a result of logic thinking. Even so I luckily never had to draw much flow charts in my life, I think that my brain somewhat works like one. I think most of us who think logically develop their thoughts in form of a tree, jumping from node to node, leaving dead ends all over because we are not able to focus on too many things at once. This is also why mind mapping is a useful technique that I started to embrace lately. It helps us to increase the amount of connections per node in our thinking and lets us discover new nodes (ideas) previously unreachable with our normal thinking.
Another technique that really helps understanding your thinking is to visualize it. Close your eyes and try to see the patterns in whatever it is you are doing (not just programming) for a second. Applied to our particular example above, we could visualize the code above like this:
Now suddenly it becomes very easy to simplify what we are doing. All we have to do is to align those nodes that are not dead ends. Visually speaking that means to make a re-arrangement like this:
In terms of code this means to get rid of anything that looks like an else statement and use a return statement wherever we hit a dead-end (return home early). Our particular example for example could be re-written as follows:
$this->Post->set('id', $id);
Assert::true($this->Post->exists(), '404');
$post = $this->Post->read();
if ($this->RequestHandler->isGet()) {
return $this->data = $post;
}
$result = $this->Post->save($this->data['Post']);
if ($this->Post->validationErrors) {
return $this->Message->add('Please fill out all fields', 'error');
}
Assert::notEmpty($result, 'save');
$this->Message->add('Post was saved successfully.', 'ok');
}
What you can see right away is that we have saved a couple lines of code, but that's not even the exciting part. The exciting part is that by recognizing a pattern in our thinking we were able to produce much simpler results! An interesting implication of this technique is that it is much harder for us to reverse engineer our logic than it is for us to produce it. This is why reading other people's source code can be difficult at times. It is not that their code is difficult, it is just that it's laid out in the way of the thought process that created it. So when you sometimes read a piece of code and really enjoy reading it, it is most likely a sign of conscious thinking and reorganization of typical thought patterns into human readable patterns.
Note: I do not use the word refactoring in this post because the word has too much association with design patterns for my taste. Design patterns itself do not make things simpler! The process of reorganizing your natural thinking does.
Regarding the second code example: I cheated a little bit in terms of saving if statements by using my Assert class to simplify things even further.
All right, I'm really interested in hearing if some of you would enjoy more posts like this. I also still have tons of behaviors and components in my backlog for publishing, but this is a fascinating topic to me right now that I would like to write more about.
-- Felix Geisendörfer aka the_undefined
You can skip to the end and add a comment.
I'm very interested in this theory and would definitely encourage you to post more. The flow chart visualizations were key in illustrating your points--they gave me a little "brainstorm rush." thx
First, let me just say that I appreciate your willingness to take the time to share gems like this. I'll be using this information today. I would like more posts like this one. If you can find time to write posts like this one, as well as publish the components and behaviors you have, that would be great.
Thanks again.
I'd also really appreciate if you post more stuff like this.
I just did something like your 1st example (nested if/else) a few days ago and wondered how i could have done it better...now i know :)
thank you very much and greetings from germany ;)
Hey Leo,
where do you live in Germany?
Hi Felix,
Great post! I agree, I think simplicity is the key. Way too often programmers code whatever they are thinking just to solve the problem and forget the step of refactoring/cleaning code/whatever you want to call it, but if left the way it is it's a confusing mess and incomplete.
Very interested in reading your future posts!
Kevin
Hi Felix,
nice article. Since I bother my co-programmers since years that they should prefer "return early" instead of "deep-nesting", I think I'll use this blog entry with it's very helpful visualization of the principle as reference material ;-)
Also useful in this respect are "continue" and "break" in loops, they help a lot avoiding to write much code for special cases. Some consider this bad practice (because they can be seen as variations of the "goto" paradigm) but that hey many advantages if used in a well-considered way, e.g. search for something in a loop and "break" when the searched item has been found (if "return" isn't possible), or jump over items with "continue" if the are not relevant for the loop, instead of filtering them before entering the loop.
Sebastian
Sebastian: Good luck convincing your peers! I also very much agree with you about the loop thing, the same idea applies there was well.
I've been taught a more strict top-down approach where the code should drop out the bottom of functions and that early and/or many exit points were generally bad practice. But I think this applies more to old VB programming where you'd often have "cleanup" sections at the bottom that always needed to execute before exiting the routine.
I do see the advantages of this "return home early" approach, though. Once my code starts to look too complicated/too many nestings for something that should be simple (or thought as a simple), I try to rewrite/refactor so that it reads more clearer. Making something human readable and understandable is certainly makes code easier to maintain later on.
Keep these kind of posts coming. If we weren't interested in becoming better coders, I don't think we'd be hear reading.
Though I would agree that it cuts lines and might seem like an advantage at first, I have to say it seems as though this approach might actually make your code less readable. If somewhere were to skim your code quickly, using nesting as a guide, they might be apt (perhaps not in the provided example, but in other situations) to completely ignore your return and may find themselves confused about the code's execution. In short methods like the one provided, it's not terrible to throw a couple returns, but in sections that are unavoidably long, more than a single return can be quite confusing. I also have to cringe at the difference in return types depending on the situation. It's always best to have a clear hand-shake between methods (clearly expected input and output of a method), and multiple returns can make that messy... That's maybe not so relevant in a loosely-typed language like PHP, but it's still good in general for project management.
Either way, please continue sharing your thoughts, I always looked forward to a post on thinkingphp.org and hope to see more here soon!
Hi Felix,
I really like this post, I run into this type of logic thinking..problem all the time.
I also very interested in your Assert class and the Message (component?). How is the Message different with the cake built in Flash? I don't think the Message is part of the cake core?
Also, how do you format the view when the Assert class throw the Exception?
Thanks,
Kien
@Bret: Hrm, but don't you think that 20 nestings of if-else structures would the code much harder to read? I think when you are reading such nested code (that should not happen all too often anyway) you will extra attention to any line and there will not miss the return statements.
In fact cutting down on the lines will help you with that.
Hi there!
I've been a fan of this "early return" style for quite a while now, even though I don't use it as much (mostly in MSSQL stored procedures and C# at work).
It really does make your code more readable and maintainable, but it's true, you have to be careful with those returns..
Great article!
p.s. regex still catching false URLs in comments? "\." ;-)
Good post.
As nearly everybody else said, KISS (keep it simple stupid). I have been doing the return early thing for a while and find it helpful.
Cake is awesome too.
@Bret: It has been my experience that having functions or piece of code that are longer than a screen should refactored (In the non-design pattern way meaning) into a greater number of smaller functions to simply code and make it easier to read.
With that in mind, missing the return statement is less likely to happen.
A colleague of me once told me that the return early method also makes it harder to debug as now there are X places where it returns and without a debugger, you have to place debugging prints at every return line to know which one is the culprit.
I do not use a debugger myself so I know what he means but it was never a source of frustration for me to have to do that.
I continue and will continue to use return early method.
Nice article.
This is great, I always enjoy reading posts that share my thoughts with code design and structure. Too many people get stuck in deadline mode, even when they're not (myself included) and don't take the few minutes to think out their code before writing. Doing what is simplest is not always the best.
More. More. More.
I think a lot of programmers would be well served to use visualization tools like the flow graphs you gave as examples. They always help me out, especially with refactoring which is what you essentially doing here.
I think a lot of programmers would be well served to use visualization tools like the flow graphs you gave as examples. They always help me out, especially with refactoring which is what you essentially doing here.
Nice post Felix. I had to face a similar situation last week. I was supposed to build a tool that is almost same as one my teammate had built earlier. The boss expected me build it fast since all I had to do is figure out the code and make changes where necessary. But when I looked into the code, I felt myself loosing in a maze! The code was deeply nested. The method names were too similar to each other, it was hard to memorize which was doing what. The guy had built the entire logic in a single controller class, making it very large in LOCs. So I built the tool from scratch. The boss wasn't happy, but he understood.
Hi
Nice way of showing why to use alghoritm ...
Do you have an error in the diagram?
In the first it is the path [Post Exists] -Yes-> [Get] -YES-> <Show Edit>
In the second: [Post Exists] -Yes-> [Get] -NO-> <Show Edit>
my teacher told me that multiple return statements are a bad idea.
what do you think?
Your post is DEAD ON! I often write complicated, nested, code that even I can't read after it's done.. although it works and all that. So understanding how we think is the most important thing.
I read the first piece of code in your post, my brain kind of understood that it was an EDIT but it didn't understand how it worked. When i saw the flowcharts everything became clear, and it became clear that it could be improved.
From now on i'll try using flowcharts to understand how i think heh.
Your idea to think about the thinking process was great. Thanks ;)
Kool! Felix your post really gives me a boost! coz this style had come naturally my way too. In addition, I would like to add that most of us name methods/functions in a way that other people might not be able to understand the way WE do. For someone who doesn't have a problem using long method names can always name methods that explain a bit more about what it's doing. This way it really turns code into poetry :) - For example, if you want to "redirect if request is not AJAX", then how about using something named like this "$this->redirectIfNotAjax()" instead of something like "$this->isAjax()" - the latter will obviously confuse someone else into expecting the function would return a value whereas it will also redirect too.
Thanks to you, my reluctance on this issue is no longer!
Nice thread!
Reading through all those comments I encountered the question about multiple return statements only once, astonishing.
You succeeded to make the piece of code more readable by avoiding nested conditions. But by using multiple return statements you went into another trap. When trying to read code including multiple return statements most people will not be able to understand the logic of it, at least if the logical conditions are complex. You are likely to miss a return statement. It also - in php - leads to return values with different data-types within a function which makes it harder to include the functionality in other classes. I personaly prefer breaks and continues here.
What do you think about this?
I appreciate the thread anyway. Would be a better world if more programmers had thoughts like that :)
Sven: Multiple return statements and different return types are good when used wisely. I can probably come up with some examples where this is not the case and code quality is decreased by using them, but generally speaking I think its worth to use those techniques they can reduce the level of nestings and therefor complexity of your code.
Wow, excellent article! I think there needs to be a lot more articles like this, focusing on "how to think" instead of "how to code a specific thing".
And design patterns actually increase code complexity, which is an undesirable side effect of their usage.
You've hit the nail on the head. For the programmer, learning HOW to think is the most important thing. Languages come and go, frameworks are born and they eventually die. But your brain ... that's gonna last you a while.
Nitpick: the two diagrams are different. The first says "Get? --yes--> Show Edit", and the second says "--no-->".
Super post..
I totally agree, often it is much more simple to have multible return statements. Some purists will say it is bad practice, but they are wrong.
thx
This post is too old. We do not allow comments here anymore in order to fight spam. If you have real feedback or questions for the post, please contact us.
Bring out the other stuff: behaviors and components.
A good idea would be to alternate the content, between programming practices & styles ( like this post... )and the heavy artillery of Cake, so we can have a peaceful digest reading the posts.
Just a thought...interesting reading btw.