What is “simplicity” in programming?

We all agree that we want our programs to be simple: in the memorable words attributed to Einstein, “as simple as possible, but no simpler”.  Kernighan and Pike’s most recent book, 1999’s The Practice of Programming [amazon.com, amazon.co.uk], has three key words written on a whiteboard on its cover: Simplicity, Clarity, Generality; and the greatest of these is Simplicity.

But what is “simple”?

I thought, or rather assumed, that we all agreed on this.  But I’ve had a minor epiphany in the last couple of days.

I’ve been reading Martin Fowler’s 1999 classic Refactoring: Improving the Design of Existing Code [amazon.com, amazon.co.uk], which I got largely on the strength of Steve Yegge’s super-enthusiastic review.  Steve described it as “a wonderful book about how to write good code, and there aren’t many books like it. None, maybe.”  So I was really keen to read this …

… and I have to say that so far, it’s been a big disappointment.  I’m on page 169, which is less than half way through; but I’ve read all the discursive, expositional chapters, and enough of the Catalog Of Refactorings to have a good flavour of how the rest of it is going to be.  And while I appreciate the clarity of thought that’s gone into both the ideas themselves and their presentation in the book, I can’t help noticing that nearly all of Fowler’s refactorings make the code more complicated by introducing more methods, more method invocations and more classes.

Chapter 1, (Refactoring, a First Example) is the most enlightening part of the book, because as usual an ounce of example is worth a ton of explanation.  In this chapter, Fowler starts with a program to calculate rental fees in a video store (yes, this dates the book!)  The program consists of three classes (Movie, Rental and Customer), but the first two of these are pure data classes, consisting only of constant definitions, data members and accessor functions — what we C programmers in fact call structs.  The third class, Customer, has a couple of members and accessors, and a single method that actually does any work: statement().  That is not a particularly pleasant method, for sure, but it’s clear enough, and would be clearer still if clarified by some “micro-refactorings”.  By the time Fowler has finished improving this program, the logic is split across seven methods in six classes (four of which form an inheritance hierarchy).

Now I am not saying that the revised code is not better in some ways.  Certainly each method is easier to read than the big one we started with; and the allocation of responsibility is cleaner.  But look at the cost: to understand how rentals are calculated, we now have to read six classes instead of one method; and because of Java’s dumb source-code conventions, those classes have to be in six separate source files.  And I would rather read one method than six complete files, thanks very much.

It reminds me of the 1980s British comedy Yes Minister — surely the funniest show ever made about three middle-aged men in suits sitting around in an office talking about politics.  Whenever Jim Hacker, the government minister, wants to slim down the Civil Service, his Civil-Service aide Sir Humphrey Appleby responds by recruiting additional civil servants to form committees whose task is to look into the possibility of setting up working groups with a remit to establish terms of reference for proposals to set up meetings to consider strategies for reducing the size of the Civil Service.  In the same way, Fowler’s response to code complexity seems to be to introduce more classes and delegate the living heck out of everything.

What’s going on here?  Is Fowler talking complete arsegravy?  Am I talking complete arsegravy, which I admit seems more likely on the face of it?  I think not, in either case.  I think what we’re seeing is that this simplicity business is not as, well, simple as we’ve all assumed.

It’s just this: I’m coming to the conclusion that one man’s simple is another man’s complex.  Fowler evidently finds it easier to read many small methods than a few larger ones; I find the opposite.  Going further, my colleague Adam Dickmeiss seems perfectly comfortable with huge functions, so long as their complexity is limited in other ways (e.g. few temporary variables).

To put it another way, both Fowler and I would like, if we could, to minimise both the number of methods, classes and source files, and their length.  But these two measures of complexity often have to be traded off, and for me, the former is most important; for him, it’s the latter.  I’m not going to claim that I am right and he is wrong: I’m coming round to the idea that it’s a matter of individual aptititude.  Some people are better at long-distance running and some at sprinting; some can appreciate the nuances of classical music and some can discern substance and meaning in punk rock; some programmers grok functional code and some imperative.  In the same way, I think some programmers’ minds are wired for dealing with many small code-chunks (methods, classes, etc.) and some for grasping fewer large objects.

If I am right about this, then there are a few corollaries:

  1. We can stop fighting about which kind of code is better.  If I ever meet Martin Fowler, I can peacefully buy him a drink (or, better, get him to buy me one).  It may be that the which-kind-of-code-is-simpler argument is not much more meaningful than which colour is better, red or blue.
  2. We should think about whether it’s good to try to concentrate similar-aptitude people together on teams, so that they all pull in the same direction; or whether it’s better to have some many-small-methods jockeys mixed in with some few-large-methods people, so that the project benefits from multiple perspectives.
  3. If you do mix your teams up, then you need to beware of getting into a fruitless refactoring war, with one faction constantly attacking with Extract Method and Hide Delegate, and the other retaliating with multi-megaton loads of  Inline Method and Remove Middle Man.  (Now that I come to think about it, I’ve been in wars like this without even realising it.)

Actually, I sort of hope I am wrong.  I think there is something appealing about the idea of One True Way of writing simple code, and I am loath to give it up.  (Just so long as everyone is prepared to agree with my definition.)  We’ve all seen plenty of code that is Just Plain Bad — that’s not at issue.  But maybe there is a whole spectrum of ways to be good.

Update (28 March 2010)

The comments on this article have been particularly provocative, and I found myself wanting to write an immediate follow-up.  So I did, and here it is.

Also: plenty of discussion of this article over on Hacker News.  Total silence on Reddit at the time of writing.

53 responses to “What is “simplicity” in programming?

  1. Aaron Ramirez

    I like the argument of this. I do agree it can be purely subjective, depending on the context. For instance, if someone is breaking up a huge function into smaller functions, simply to make it more “readable”. If you are using .NET, you can’t say that doing this can hurt performance due to extra method calls, since the code is likely to be optimized into 1 function call. With this being the case, it is purely opinion.

    Now, if breaking up this huge function into multiple calls is in the name of code reuse, it is no longer subjective. The fact is, by staying DRY, the program is less likely to see bugs with future updates. Other factors for breaking up classes and functions, can be to decouple business logic from data retrieval. It may not be a simpler program now, but it will be closer to “simple as possible”, if you need your program to work with multiple data sources.

    So I agree, simple can sometimes be a matter of opinion. But that is rarely the case with software development. More often, simple is relative.

  2. Pingback: Refactoring wars and how to avoid them: what is “simplicity” in programming?

  3. I once had this same argument with the teacher of my first programming course. I received a poor review on an assignment because my code was ‘too convoluted’, despite the fact that mine was the only one in class to work properly. I took offense due in no small part to the fact that he was barely older than i was, and I’m ashamed to say the argument escalated into a shouting match. That was years ago of course and since, i’ve come to the same realization as you. People’s minds work differently, therefore they code differently. Inevitably the quality of the product is what matters, right? That being said its nice to hear from someone who thinks the same way I do.

  4. Carlos Azevedo

    I think Simplicity is more a function of the tools used than of one’ skills; “print ‘hello world'” (python) is simpler than “#include int main() { printf(“hello world”); }” (C).
    Obviously a not-so-good programmer might create complex code for a simple problem (Bad Code), but not even the best can create simple code for a complex problem (God Code).
    I much rather prefer Clarity as a goal; that depends solely on one’ skills and to me it’s the first goal any software architect should persue; clarify the problem, the steps required to solve it and the code itself.
    Clear code means maintainability on the long haul and to a professional programmer that should be paramount.

  5. If you read Steve Yegge’s later posts (especially the ones focused on dynamic languages) you’ll see how he talks about refactoring and design patterns as a way to get around inflexible and badly designed type systems (mainly Java’s) and how many of the problems go away in dynamic languages. Now while I’m not going to say that dynamic languages *don’t* need the occasional redesign and refactor, they do minimized the refactorings required due to fighting the language (the inheritance hierarchy perhaps). Though, I haven’t actually read Refactoring myself, so I might be very off topic.

    I also do agree with your point and the problem of making programs simpler is very nuanced and related to the particular programmer. Just goes to show that computer science isn’t a science and it’s not about computers.

    Cheers.

  6. I agree with Fowler on this one. Using the Single Responsibility Principal will mean you will break classes and functions into smaller bite sized pieces. Then your unit tests are testing the specific requirement your method is accomplishing. Limiting variables scope within a function doesn’t limit complexity. Limiting the number of if’s, loops and number of things within a function limits complexity.

  7. I am dead on with you on this. People have misused inheritance (and multiple inheritance) yielding to a situation today that modern languages are avoiding support for both. Duh! A few developers who use them properly will suffer in the long run (as I already do since Java/C#/etc. just cannot do what I can do with C++) since these will not be available except to implement interfaces. Oh, right today I reviewed a piece of code where there was an interface and a single class implementing it! Duh! (Would they now remove interfaces five years down the road?!)

    >> To put it another way, both Fowler and I would like, if we could, to minimize both the number of methods, classes and source files, and their length.

    Here are my rules:

    1. Minimize the number of methods, classes, etc. just like you said.
    2. Minimize ‘not’ the length of functions, but the total length of the code!

    These two can be contradictory, so I make #1 carry higher priority. So no reduction of size of code by extracting common code out in unexpected and counter-intuitive ways.

    I once wrote a long function that printed to 20 pages! Yet, it was simpler code than having to divide it to multiple classes etc. (which truly-speaking was not even an option for me). The net size of the code I had was overall smaller. And my interface was damned simpler — just one function. Code was well documented, and no bugs were ever found in it in the entire history of the product.

    This approach clearly has less overheads since you have to write limited number of test-cases, do not need to spend lines in each function making sure arguments are correct, etc.

    Rule 3 I have is that if at least one of the interface and implementation has to be complex, it should be the implementation rather than the interface. This way you simplify things for the future — the overall code complexity does not grow as fast with time as the overall size of the code increases.

    So simple guidelines, yet often no agreement!

  8. I did not read the book, but one of the huge avantage of the refactored classes would be testability.
    Idealy , you would not have to read the code of all the methods as the name should tell you by himself what is it doing.
    I also haste whe i have to open 20 files to understand how things work maybee we need an inlining tool to read the code ?

    Chris

  9. come on, either you write many small functions, or you dont abstract pieces and glue them in one place, you still have the same processes going on in there.. except that with small functions, you are having overhead from functions’ headers..

    so how can we split code into meaningful atomic operations, yet keep the good overview with all the meaningful context lying around? you just have to write down the pros and cons of both styles, then choose only positives, and try to find a solution that satisfies all positive issues.. that’s how world works, there is always a solution.. and if you answer this, you’ll get that ‘One True Way’

  10. “It may be that the which-kind-of-code-is-simpler argument is not much more meaningful than which colour is better, red or blue.”

    Isn’t this at odd with one of the main goals of good code: maintainability? I want someone else to be able to maintain the code I wrote, not simply Yours Truly maintaining it 6 months later.

    I may never meet this someone maintaining some code I wrote (e.g. if I move to another company), hence balacing the team culture, as you propose in point 2., seems difficult to do in the long run.

    This does not mean that I have a good definition of simple code either, but it may be worth trying to find one!

  11. The biggest improvement from refactoring toward small pieces of functionality, in my experience, is that testing becomes much easier and faster.

    Testing a method that is 100+ lines long is relatively difficult because of all the possible branches during execution. If nothing else its just harder to consider all the possibilities if its all lumped together.

    If you can refactor, test all the resulting support methods/classes, and then stub those methods/classes the tests will be shorter, much more directed, require less setup, and be easier to read/comprehend.

    Purely anecdotal, but its something you didn’t mention in you article.

    Disclaimer: I work primarily with ruby so my test code ends up somewhere between one and two times the size of the code it supports. As a result I need to be able to create/alter tests quickly.

  12. Bob: yes, of course it is true that limiting the number of if’s, loops and number of things within a function limits complexity; but why would it not ALSO be true that limiting variables’ scope within a function limits complexity?

    Carlos: I certainly agree that using the right language (by which I mean a terse dynamic language) makes some kinds of complexity evaporate. But not all: once that happens, you’re left with the real, irreducible complexity of the problem itself, and that still needs to be addressed.

  13. I think the argument for Fowler’s code style might go like this:

    1. Software systems are large, so it will be hard to understand a complete and reason about a complete code path
    2. Thus, we should break up our code into small modules that can be individually understood
    3. Polymorphy makes it easier to introduce variation into systems as it encapsulates the changes into one code unit (class).
    4. So we should seek to encapsulate behaviour into individual, small, polymorphic methods

    I actually think that is not a bad way of programming. The one big honking 300 SLOC method will be inherently difficult to understand, reason about, and (maybe most importantly) test and change. You cannot just look at a particular piece of code and decide if it is right or wrong according to a small set of invariants that must hold for the class – you have to understand all the other uses of its fields, or whatever classes might be thrown at it. If you get your OO design right, you end up with a system that is reasonably easy to understand, once you have learned the different concepts (root classes), and their responsibilities.

    In my experience, systems tend to get more complex and are constantly changing. If you have large systems with hundreds of KLOC, I find it difficult to imagine how it would work without this small polymorphic OO method approach.

    The problem with books like this and their examples is that the technique is geared at e.g. a hideously complex loan system, but to keep the examples understandable they must be so short that it kind of defeats the point.

  14. I agree that simplicity is a completely context specific notion. However, in recent years a new style of programming has entered the mainstream (see Fowler, or Robert C. Martin). It favors finer grained classes and shorter methods which many of us find aligns better with object oriented principles.

    Long methods and coarse grained classes quickly fall out of favor as soon as you consider unit tests. It is simply a lot easier to unit test small classes with tight cohesion. Since some older programming communities like the C/C++ one typically don’t prioritize unit tests as highly as others, they don’t have much incentive to change their designs. And, as Fowler writes, you shouldn’t be refactoring without unit tests anyway ;-)

    BTW: Even in Java you don’t need a new file for each class.

  15. I think the key difference here is that you are using `simple` to describe how easy it is to read or understand the code. Whereas Martin Fowler, imho, uses `simple` to descibe how easy it is to *maintain* the code. The likelihood of changes proliferating throughout all of the modules in a system, say.

    Also, I notice you call yourself a C programmer. It strikes me that another possible cause for the discrepancy may be that you are just more comfortable with a procedural architecture than you are with a truly object-oriented one.

  16. as Phil said above, and even more so, functional programmers.

    Hopefully when you “grok” Lisp you would get the idea of simple, composable functions/methods

  17. I think there’s a lot of ‘real life’ stuff influences which code is ‘simpler’ for you / me / the next dude.

    I run a team, work across several projects and am on call for support to a couple of clients. This means I rarely get more than a short period of coding uninterrupted. (I also have a kid so evenings and weekends roll pretty much the same.)

    So – I go for the ‘fewest files open’, ‘fewest methods open’ approach. Granular code allows me to consider more code ‘done’ more quickly. Once it passes its tests it can be set to one side and never touched again. It means that in my little chunks of coding time I can get stuff ‘finished’ and forget it.

    Long methods, complex controller classes… they’d sit open on my computer for days, and I’d inevitably mess up things that were already working. Or at least waste time looking at code that was already working.

    So I favour short, very longwindedly named methods, and granular classes with a single, unambitious purpose each. I personally believe that this actually makes the code easier to understand for someone coming in. A function called ‘moveTheViewToTopLeftCorner’ is easier to grok than thing.x = 0, thing.y = 0… my assumption is that a new programmer on the project can understand the code, but its motivation / purpose is valuable information to them better captured through method names than comments.

    I actually love Fowler’s book and have a poster of prompts to refactoring by my desk based on his suggestions (many of which are two way!).

    But what I’ve come to realise is that the me of 10 years ago that had fewer calls on my attention could code in a way that today’s me can’t. But that doesn’t mean that my approach is right for you – as you say, it’s personal.

  18. While I understand your point about over-engineering, I believe that it’s not as much a matter of preference as it is a matter of context.

    In Fowler’s example, I am pretty sure he understands the refactoring as a way to make the code more amenable to expansion. If you have six or seven classes, you have more legroom to expand the code than with a single method.

    If you take the portion of the code out of its bigger context, it may look like refactoring it is over-the-top.

  19. Stevey also wrote in another article how his coding style has changed over the years, as his capacity to manage complexity increase :

    http://steve-yegge.blogspot.com/2008/02/portrait-of-n00b.html

  20. Those are great guidelines Alok. It is what I am doing as well, although I couldn’t name the rules before.

  21. It’s interesting that John Blender says that one advantage of Fowler-style lots-of-small-methods programming is that it’s easier to write tests, whereas Alok says that the few-bigger-methods approach “clearly has less overheads since you have to write limited number of test-cases”. I’m not sure what to make of this disconnect, but I think I’m going to read it as support for the idea that different people just have different natural aptitudes that make them more suited to one or other of the styles.

    I have to say that, while I am a big fan of regression-testing, the idea of writing twice as much test code as application code, as John does, is totally alien to me. ScottKit has about 15% as much test code as application code, and that feels about right to me — enough to get 90% of the benefits of testing, but not getting into the realms of diminishing returns.

  22. (A quick point of clarification for Phil Booth: yes, I called myself a C programmer in the article, but it’s been a decade since that was my language of choice. Since then I’ve mostly used Perl, and more recently Ruby, and pretty much all my programs have been … well, if not exactly object-oriented, than at least object-infested. So, no, this isn’t a cause of the discrepancy. In calling myself a C programmer, I was just using a lazy shorthand.)

  23. Pingback: What is “simplicity” in programming?, redux « The Reinvigorated Programmer

  24. Phil: I really *am* a C programmer, preferring it to any scripting language out there other than the shell, Python, and Lua; and in my day job I can’t use the latter two because too many of my workplace’s stuck-in-the-mud clients don’t have either Python or Lua installed and refuse to ever install anything for spurious ‘security reasons’ (yes, that includes things like CPAN modules).

    So I have to use C a lot, and wrote my own testsuite engine in ksh (sort of like DejaGNU only with more focus on simplicity for trivial testcases). And, guess what: I’m a huge fan of small functions. If I have a function bigger than a screen or two it’s a sign that something is seriously wrong with my design, in my eyes, I design systems specifically so they can be tested more easily, often with a low-level layer providing functionality in a functional style (depending only upon arguments to one or more functions), and a higher layer linking that to all the databases and other automation layers needed for the lower layer to connect to the rest of the system, *specifically* because that means that every nuance of the lower layer can be tortured automatically without being affected by changes in the rest of the system.

    I have trouble comprehending 300-line-long functions, particularly when they were written pre-C99 so have all their variable declarations at the top, even more so when they were written by people who think that all variable declarations in C must go at the top of the *function*, not the block (a depressingly common misconception). I have even more trouble comprehending why anyone would want to write 300-line-long functions. The Unix philosophy is to have small components that do one thing well: surely this applies just as well to functions as it does to entire programs?

    I’ve seen people do things like writing entire interpreters in a single switch statement in one function. Unless performance is paramount, I’d much prefer a jump table.

  25. Nix wrote, in the context of C programing: “If I have a function bigger than a screen or two it’s a sign that something is seriously wrong with my design”.

    I just had a thought. “A screen” these days means perhaps 60 lines (the number I happen to have in the emacs window that’s on the other side of the screen from the browser I am typing this into). I agree that a function of 120 is, if not a red flag, then a mild odour that suggests room for improvement. But when I started programming C on Unix, it was on 24-line terminals. Take out the two lines that emacs uses (status line and minibuffer), and I, like the rest of my generation, was seeing 22 lines of code at a time. I think we can all agree that a 22-line function isn’t a code-smell.

    So I am guessing that I grew up with the idea of multi-page functions as a natural and normal thing, whereas maybe programmers of more recent vintage are used to being able to see the whole of each function at time, and have trouble when it’s not so?

  26. “I think we can all agree that a 22-line function isn’t a code-smell.”

    Then have a look at contemporary literature, you’ll be surprised. According to Robert C. Martin’s “Clean Code” (which is quite influential these days), 10 lines is the new suggested maximum. You may find you’re even more out of touch with modern software development then you think.

    It remains to be seen if the new ways are better than the old though :)

  27. mafr: 10 lines is absurd ;)

    I am a C++ programmer and the standard template library (which became part of the C++98 standard library) has influenced my coding style a lot.

    Here there is a separation of data structures and algorithms. So either I write a data structure or I write an algorithm (not a class that mixes it).

    How long the functions are doesn’t matter, the API is what matters, and the API is what I write my tests for (not private/internal/helper functions).

    An API would be the data structures and/or algorithms that solve a particular problem, for example a data structure could be a stack, a date, a point, a matrix, etc. and it should provide a minimal interface for manipulating the type, sort of the axiomatic operators that can be used with the type.

    This makes the data structure easy to test extensively and easy to do a full replacement, should the need ever arise (e.g. replace the array type with one that does copy-on-write or similar w/o the need for having the replacement type implement all sorts of “additional methods” that has nothing to do with the axiomatic array operations (which are add, remove, clear, iterate, lookup, and count).

    All but the axiomatic operations should be provided as standalone functions (algorithms) and preferably be written as type-neutral (if possible). E.g. the standard library in C++ provides many standard algorithms like sort, find, binary search, reverse, etc. which can be used with pretty much all the container types.

  28. Pingback: Top Posts — WordPress.com

  29. Your choice of picture to appear immediately above the word “arsegravy” was… disturbing.

  30. Not as disturbing as your pink-heart-with-T-rex-hindquarters avatar, though.

  31. I think aodgaard has cracked this:

    “How long the functions are doesn’t matter, the API is what matters, and the API is what I write my tests for (not private/internal/helper functions).”

  32. I don’t think aodgaard has cracked this :-) It’s certainly true from a certain point of view that the API is all that matters; for someone who is using my library, the number of classes and length of functions behind that API is of no importance. But the issue here is what the codebase is like for people who are working on it, not just with it.

  33. I think simplicity is much less important than readability. If you the structure and function of the code do not align, you can pass all the unit tests but have no idea of how to find bugs or make improvements to the code. Wasn’t Dijkstra’s original point about structured programming that structured programs were easier to read than unstructured ones?

    Of course, it would be nice if there were better code reading tools. When I was forced to use C++, the first thing I did was write a little parser to produce an EMACS tags file with the various classes and methods so I could hop from invocation to code and get overviews of classes and their hierarchy. I am surprised that this isn’t part of the standard EMACS release. I submitted my code to GNU, but the last time I met Stallman he had short hair and threatened me with physical violence (his terms).

    Personally, I’ve always liked middle out programming where the idea is to design a language for solving your problem, then implement it with classes and subroutines. Then, you can work at two levels: (1) making your solution easy to understand and (2) cleaning up the language implementation. LISP makes this kind of thing easy, but I first learned this approach using FORTRAN II on an IBM 1130. I think the green Louden book with a picture of a ten pound, 1 MB disk cartridge on the cover discusses it nicely.

    I don’t have much to say about the length of methods. Some numerical code I have written is easier to understand with long methods because that’s the way the algorithm is described and that’s what anyone familiar with it is going to expect. Breaking it into chunks is just going to make more work for any maintainers.

  34. “I’ve always liked middle out programming where the idea is to design a language for solving your problem, then implement it with classes and subroutines. Then, you can work at two levels: (1) making your solution easy to understand and (2) cleaning up the language implementation. LISP makes this kind of thing easy, but I first learned this approach using FORT[…]”

    I could have sworn that sentence was going to end in “H”!

  35. “all of Fowler’s refactorings make the code more complicated by introducing more methods, more method invocations and more classes”

    That isn’t the only measure of simplicity. The number of moving parts is the same–where those parts are located, how they are testable, and how they’re decomposed are better measures.

  36. Martin Hedenfalk

    I don’t consider the length of a function a sign of complexity. I’m much more concerned about the width of a function. With 8 space indent and sticking to 80 columns, it’s easy to spot when a function grows too complex.

  37. No, Dave, of course they are not the only measures of simplicity. If I implied that they are, then I didn’t make myself clear. But they are some of the measures, and they need to be taken into account in reaching an aggregate simplicity assessment.

    Martin Hedenfalk, good point about function width — I’d agree that it’s more often a good correlate of subjective complexity than length is. Maybe we should multiple them together to yield a “function area” metric, or perhaps something like width x sqrt(length) would be better.

  38. Mike Taylor: By API I mean everything that is “public” in your own internal code base.

    I am pretty big on separation of concerns, so much that I tend to create self-contained submodules with an “API” that should generally not exceed 3,000 lines of code, have a well-defined responsibility and a well thought out API.

    I write the unit tests for the submodules, and it is the API of the submodules which I consider key to managing the complexity. While I of course have standards, how each submodule is implemented (code wise) is of little concern, because if the API is good (which the tests sort of help assure), I should be able to rewrite it fairly easily, should the need arise.

    A submodule can be a traditional procedural API, data types, classes, or a mix of the above, as long as it is all there to solve the defined task of this submodule.

  39. Simplicity is key — and is personal, but one also has to remember that the simplicity is not just for the sake of the original author of the program — at some point, someone else will have to consume our canine daybreaker meal, so it’s a good idea (I think) to bear that little nugget in mind.

    Personally (and I just know that I’m going to have flameback from this from someone out there), class inheritance isn’t something that I do very often. Conglomeration, yes — but inheritance, not so much. Not that there isn’t a place for it — just that it’s generally only useful when you have a class which does most of what you want but not quite, so you want most of what it has to offer, but differently.

    Personally, I don’t get much out of the multiple layers of classing “just because you can” or “just because it may conceptually be logical”. Do it if you must, avoid it if you can.

    Also a little gem I picked up somewhere (and this one makes more generic sense): apart from the obvious time to break out a function (or method, whatever) to do something — the “something” will be done repeatedly — another good place to make functional breaks is where you keep each function “less than a page long”. Now, that’s also subjective, but it starts making sense when you do step over the page boundary: you’re now unable to scan over the entire function in one go. At this point, I may find one or more particularly hefty loops and break them into functions of their own — just so that the main function looks simpler and debugging becomes more atomic. Because, whether we want to admit it or not, the average programmer actually spends more time debugging than writing — so it might as well be a pleasant experience (:

  40. Pingback: The collapse of complex computer programs « The Reinvigorated Programmer

  41. I’ve read this article and the referenced article and noted that neither have pictures of a cat. This may explain why reddit hasn’t given said articles the attention they deserve. Please try to understand social networks before making reference to them.

  42. Pingback: TapaGeuR » ITGIF – “IT-God” It’s Friday #15

  43. found these comments most interesting. From them I infer that the writers span a broad spectrum. As a software engineering academic, with an earlier computer sysems and CAD background, I like to build code generators to implement my code wherever possible. My major sources of inspiration were Bachman’s daa models and Shlaer and Mellor’s Object Life Cycle (state) models. By modeling the problem more abstractly, the models provide a key to understanding how to partition, view and test the code itself.

    Subclasses split a function into subclass variants. Ideally, each sub-method is more cohesive than their aggregate and a fraction of its size..This eliminates one case switch per level of subclassing, which is amply justified ONLY if you understand and follow the class model’s partitioning of the code base. Each unit test is simpler than their aggregate over all subclasses. To me, aggregation of different classes into compositions of data is at least as (if not more) significant than inheritance hierarchies as a key to understanding code behavior.

    With subclassing (C++) or without it (C), control flow internal to a method or function is easier to deal with and extend if state variables are recognized. Branch-controlling variables whose values are
    not set locally influence behavior from places that may be far away and separated in time.. Iff you encounter them, it is far better IMHO to create a state model of the control flow or dynamic behavior
    within the function, and encode such control variables as part of the single
    state variable n this model.

    Another advantage of class and state modeling is that the remaining code
    fragments diminish to actions within a single state, with little or no control branching or looping within each action. Such simple ‘methods’ do not require a complex programming language.
    OMG’s UML/MDA standard supports both data/class and state/behavior models.
    Unfortunately it does not emphasize separation of control flow from action method coding, which would reduce its dependence on the ‘action’ implementation
    language.

    This state model, like the class or data model, also becomes part of the documentation. Without it you cannot understand the program. With it, the program becomes testable at a new level –
    that of the state transitions. All or most control variable updates are modeled as state changes. These are visible (and traceable) at the transition diagram level. State transitions are easily recognized
    as the cause of all or most control flow diversions even with intervening
    time delays. Although more complex, message passing among threads
    can also be modeled at the state diagram level. This permits a smoother transition to concurrent programming for newer multi-core computer architectures.

    Caveat: to keep models small, a hierarchy of nestable state diagrams must be supported by the tool you are using. Tools are particularly important to keep
    state models in synch with test code. Ideally, both data and state models will be maintained by a common version-control system.

    Bob Lechner

  44. Pingback: Slicing your 2D class/function matrix vertically or horizontally « The Reinvigorated Programmer

  45. By the way, research has shown that the optimal size for methods as measured by lack of bugs is between 150 and 500 lines. Yes, those numbers are correct, though they predate TDD.

    For people fond of many small classes and methods, I wonder how long do they take to understand _what_ is being done? I’m not being sarcastic here: I like small methods myself, but I _hate_ jumping around when reading code.

  46. Pingback: Frameworks and leaky abstractions « The Reinvigorated Programmer

  47. could you please get rid of all these annoying sushi photos all around this website?? please?!

  48. Not while there is breath in my body.

  49. Pingback: Testing is not a substitute for thinking (binary search part 3) « The Reinvigorated Programmer

  50. Me, myself and I

    I don’t think choosing Fowler’s example as an example for simplicity was a appropriate. The refactorings Fowler presents in his book are not just about simplicity. They are about the optimal compromise between maintainability, flexibility and reliability. Essentially, they are about changing existing code towards optimizing maintenance and usage cost. Which is in no way about simplicity. If simplicity would always lead to the lowest cost, there’d be no robots, no PCs, no modern cars in use anywhere. That’s probably why there’s no popular code metric about simplicity (There are a few about complexity, though).

  51. Essentially, [Fowler’s refactorings] are about changing existing code towards optimizing maintenance and usage cost. Which is in no way about simplicity.

    On the contrary, I would say that they are absolutely about simplicity. Unless you’re arguing that complex code is just as easy to maintain as simple code. Sure enough, robots, PCs and cars are made as simply as possible. In the case of intrinsically complex objects, there are obvious limits to how simple they can be; still, designers strive to make them as simple as possible.

  52. My favorite online english dictionary, namely en.wiktionary.org, does not know “arsegravy”.

  53. Pingback: Programming Books, part 5: Programming Pearls | The Reinvigorated Programmer

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s