Live data from Hacker News

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

reprog.wordpress.com

1–10 of 35 posts

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

#3
post #2

Surely one long function is very much harder to test than several shorter ones? So in the context of unit-testing at least, testability is in harmony with Fowler's definition of simplicity. Seems like a nice goal to me.

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.

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

#4
post #2

Surely one long function is very much harder to test than several shorter ones? So in the context of unit-testing at least, testability is in harmony with Fowler's definition of simplicity. Seems like a nice goal to me.

Yes.

And with testability comes flexibility and maintainability. I think the author is focusing too much the simplicity of familiarization and conceptual weight where, very often, the real challenge with imperative code lies in maintenance.

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

#5
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 code?

I agree with the author that this is ultimately a personal preference. One guideline that I appreciate is that your code should operate at a consistent level of abstraction. For instance, in the routine that defines the business logic, the details of the protocol used for persistence should be "somewhere else." This complicates tracing the execution of the program, but it makes understanding the intent of the business logic easier as there are less "implementation details" to ignore.

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

#6
Personally my brain has an easier time grasping {TaskA(); TaskB(); TaskC();} rather than a 750loc block of code. Yes, multiple source files are annoying, but there's plenty of tools out there to help (ctags and vim is enough for me).

But the more important reasons to strive for high cohesion/low coupling are: Future changes are generally easier when you have well defined blocks instead of a birds nest of code, unit testing practically writes itself, and you have a better chance at isolating a problem to a module if it's responsibilities are few and well defined.

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

#7

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?

When you trust the abstraction. For example, on the whole we trust the filesystem abstraction, we rarley try to inspect the phisical location of the bits on the disk - the filename is sufficient, we can treat the fielsystem as a black box.

On the other hand, if you don't trust the code, you're going to want to read every line, and that's easier to do if all the code is in one method. An abstraction is a liability if you can't trust it.

Re testing: it's easier to trust a well tested function, so splitting up code to make it easier to test, and then testing it, will allow you to ignore it's implementation. Suddenly it isn't logic spread across six classes, but one class using some utility methods.

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

#8
post #2

Surely one long function is very much harder to test than several shorter ones? So in the context of unit-testing at least, testability is in harmony with Fowler's definition of simplicity. Seems like a nice goal to me.

Yes. And with testability comes flexibility and maintainability. I think the author is focusing too much the simplicity of familiarization and conceptual weight where, very often, the real challenge with imperative code lies in maintenance.

[deleted]

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

#9
post #3
post #2

Surely one long function is very much harder to test than several shorter ones? So in the context of unit-testing at least, testability is in harmony with Fowler's definition of simplicity. Seems like a nice goal to me.

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.

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

#10
There's a spectrum with respect to abstraction. Too little, and you end up with a brittle blob of code where the multiplication of each axis of change and parameterization causes an explosion in state changes and maintenance costs. Too much, and you end up with too many indirections, lost performance, and an additive cost of change and parameterization in each axis that dwarfs the complexity of the underlying operation.

The happy middle is "just right", but it's hard to recognize or achieve without some experience of either extreme. And even then, the chosen point might be biased towards less abstraction for performance reasons or more abstraction for composability and reuse reasons. But really good use of abstractions (ideally including at the language level) ought to reduce the amount of compromise needed.

Post reply on HN