Live data from Hacker News

Refactoring wars and how to avoid them: what is "simplicity" in programming?

reprog.wordpress.com

11–20 of 35 posts

Re: Refactoring wars and how to avoid them: what is "simplicity" in programming?

#11
From the first chapter of 'Refactoring': "Was it worth it? The gain is that if I change of the price's behavior, add new pricess, or add extra price dependent behavior, the will be much easier to make."

Massive functions start out as small and then large ones. If a business logic function has to grow every time there's a new rule that could live behind an abstraction, it's on the path to becoming massive.

Re: Refactoring wars and how to avoid them: what is "simplicity" in programming?

#12
Fowler's book is about simplifying mainentance and testability, not (necessarily) simplifying the actual code. He doesn't even claim his techniques are the best way to start programs, hence the "Refactoring to" portion of the title. Also, it's specifically about object oriented design patterns so the examples aren't intended to apply to other paradigms.

Re: Refactoring wars and how to avoid them: what is "simplicity" in programming?

#13

this entire blog post reduces thusly: "hiding complexity with abstraction and encapsulation is not simplification, but further increases cognitive load as the abstractions must be undone to fully comprehend the function of the code." It is an interesting point, sure. I think the example as given makes his point fairly well. The question becomes: when does hiding complexity improve your ability to reason about the cod…

Is the goal to hide complexity? Any non-trivial program is going to be complex no matter how you refactor it.

Re: Refactoring wars and how to avoid them: what is "simplicity" in programming?

#14
We are far too willing to dismiss things as mere "personal preference" in this industry. There may be competing theories all supported by some empirical evidence and sound logic, but some claims are directly contradicted by hard data. Those claims are not just a personal preference for the best way to do things. They are measurably, objectively wrong, and failing to say so is just being nice because we don't want to criticise someone.

On the evidence I have found to date, I am coming around to the view that the style of writing many very short functions (say up to 5-6 lines) with little complexity in the logic (say just a single level of nesting) is one approach whose claimed superiority is directly contradicted by empirical data. For example, McConnell discussed the number-of-lines issue in Code Complete years ago, citing multiple studies. Anyone can find still more by investing a few minutes in Google Scholar searches.

Alas, that does not stop bloggers, consultants, trainers and book authors from advocating this programming style, even though it invariably results in the kind of incohesive "spread" that the article mentioned.

Re: Refactoring wars and how to avoid them: what is "simplicity" in programming?

#15

this entire blog post reduces thusly: "hiding complexity with abstraction and encapsulation is not simplification, but further increases cognitive load as the abstractions must be undone to fully comprehend the function of the code." It is an interesting point, sure. I think the example as given makes his point fairly well. The question becomes: when does hiding complexity improve your ability to reason about the cod…

> The question becomes: when does hiding complexity improve your ability to reason about the code?

How about this: "when the degree of complexity hidden is greater than the extra complexity introduced by the abstraction mechanism"?

Edit: Here's an example to show what I mean. Suppose we have a 2D array representing a matrix of values and we want to print it. We could write an algorithm like this:

  function print_matrix =
    for each row i
      for each column j
        print_element i j
Or we could write something like this:

  function print_matrix =
    for each row i
      print_row i

  function print_row i =
    for each column j
      print_element i j
In the second version, we might have shorter functions and less nesting, but we haven't significantly lowered the level of abstraction between one function and the other, so there is little real benefit. On the other hand, we have reduced the cohesion because now the reader must follow the logic through two functions instead of one, and this is bad. There is too much extra complexity created by introducing the second function and not enough hidden complexity because the levels of abstraction aren't much different, so breaking out the inner loop is a bad trade-off that makes it harder to reason about the code.

Re: Refactoring wars and how to avoid them: what is "simplicity" in programming?

#16
I think the point is avoiding complexity until absolutely necessary. Splitting code and creating abstractions "because it will make doing X easier in the future" is often the wrong thing to do. The right thing imho is to split it when you need X now, not the future.

Re: Refactoring wars and how to avoid them: what is "simplicity" in programming?

#17
post #9
post #3

Earlier quoted context omitted.

I'm with Fowler on this one as well. If you divide out parts of the logic of a single complex function, you can take it one level at a time. Furthermore, if you've divided it well, you can more easily reuse logic. Having a single monolithic function is like having a single monolithic program: usually a bad idea. Granted, I don't like spreading related logic over several files, but that is Java's fault.

For Java I agree, more and shorter methods are better. But then I see Haskell programs with zillions of one-line functions and higher math to do trivial things, and then I can understand where he's coming from.

I'd suggest that the important thing is not how many lines a function has, but whether it represents a single, cohesive idea.

Haskell functions aren't shorter because someone decided one day that they should be, they are shorter because Haskell is relatively expressive in some areas. Concepts in suitable areas that would take several lines to represent in another language might take only a line or two in Haskell.

On the other hand, there are other areas where Haskell takes pretty much the same amount of lines as an imperative language, and still others where Haskell's model isn't such a good match and it might require more lines.

Re: Refactoring wars and how to avoid them: what is "simplicity" in programming?

#18
The author's criticism of Fowler's refactoring:

But look at the cost: to understand how rentals are calculated, we now have to read six classes instead of one method... Fowler evidently finds it easier to read many small methods than a few larger ones; I find the opposite.

This raises the question, do we all have our own definition of good code?

Several books have tried to formalize what is good code (he mentions Refactoring, Code Complete also comes to mind). I enjoyed those books, but I'm often reminded of what my CS professor once told me: good code is a matter of taste.

In the example he cites from Refactoring, my taste is more like Fowler's. I think it's easier for bugs to hide in long methods than short ones. Plus, Fowler extracted some distinct concepts into their own classes-- things like prices. Price formulas are likely to change, so I say the cost of extracting that class is well worth it.

It seems to me that ultimately, Fowler and others are not claiming to have found the secret to "good code;" rather, they are trying to influence people's taste for what they consider good code.

Re: Refactoring wars and how to avoid them: what is "simplicity" in programming?

#20
I think you are wrong. It's not just individual taste. What matters is how well functions are aligned with units of change and reuse.

Simplicity is having to think about a smaller number of items and dependencies when I want to change/extend/reuse code. If there are many functions and classes but I have to touch all of them whenever I want to make a typical modification, then it's worse than having everything in one function. Conversely, if a more granular design allows me to ignore most of the code and just change one simple function or even just parameterise it differently, that's simplicity.

But there is a snag. Even if the design aligns well with units of change and reuse, and I would have to make just one small change in one small function in order to have the desired effect, I don't necessarily know which of a large number of functions it is. I might not even know whether or not such a function exists. So I have to understand how everything works together in order to benefit from well designed code.

That leads me to the conclusion that better programmers who do understand the system and its interdependencies benefit from small units provided they align well with units of change and reuse. Bad programmers have to look at everything every time anyway, so they might find it easier to look at one large chunk of code.

Post reply on HN