
Semantic Compression - rinesh
https://caseymuratori.com/blog_0015
======
jnwatson
I've been programming for a long time now, close to 40 years. Back when I
first learned programming "top-down programming" was the rage. This
essentially means you take your top-level functionality, and break down that
into steps, each of which become its own module, and you keep decomposing each
step into substeps unto you have code.

There was a particular Zen, a flow, about top-down programming. You roughly
knew the next thing you should work on, and the conceptual stack of things you
had to remember were tracked easily by the stack of procedure names.

This is fairly close to what the author is talking about. "OO design" has been
a disaster, but as a basic tool of coupling data with behavior, it works fine.
If a class happens to match a real-world thing, well that's just a
coincidence. A programmer's job is to get the computer to do what you want,
not somehow model the world.

At the same time, the right abstraction can make all the difference. While
tactically, my process is very similar to the author's, what turns workmanlike
code into true craft is finding the right concept that dramatically reduces
cognitive burden on the programmer.

~~~
blackflame7000
Agreed. Something that got lost in the JavaEE world was that design patterns
are there to make the problem easier to solve by leveraging the solution to a
similar problem. Instead, many JavaEE programs are just class after class
after class all starting with the same prefix and having some new verb
attached to the end like "Manager"

~~~
AnimalMuppet
<nit>

"Manager" isn't a verb.

</nit>

~~~
zaarn
manager ( _verb_ ): becoming a java class

------
abainbridge
I agree with everything he has to say but there's an important caveat missing:
In his example, the code he starts with is trivial to understand. I can read
through it linearly. I can see how the variables are used to achieve the
layout. The functions draw_title() and draw_big_text_button() have obvious
meanings, partly because I can see x and y coords being passed in.

Comparatively, the code he ends up with is hard to understand. If I was new to
the code, I'd be wondering what layout.window_title(title) does. I'd have to
lookup the definitions of Panel_Layout data structure and window_title()
function. Instead of reading linearly, I now have a tree traversal to do. That
is harder.

However, he's not wrong. The changes he made allow more things to be added to
the UI panel without the code becoming an incomprehensible mess.

Let's call the original code the linear one. I think the reason his
refactoring is good is because the linear function would otherwise have passed
a threshold where it was too complex to fit into the working memory of the
programmer. The tree traversal exercise he is forcing the next programmer to
do serves a purpose. Each function and data structure he introduced is small
enough to fit in the programmer's working memory. After looking up those
definitions, their (simple) behaviour should be able to be parked in the
programmer's medium term memory. Once that investment is made, use of working
memory is reduced, freeing up the possibility of adding more stuff to the UI
panel function without it passing the threshold.

There's a trade-off. In some ways he made the code worse. But it was
necessary. We should always be asking ourselves if the abstractions we are
introducing are necessary. Understanding the constraints of programmer's
brains is vital to being able to make that judgement.

~~~
fouc
I think that functions should be small & minimal to no side effects &
trustworthy. That way you can see something like "layout.window_title(title)"
and not need to go read that code because it's not necessary - unless you were
specifically making a change in that area. Even if it can make debugging
slightly trickier with the extra tree traversals, it also makes debugging
easier at the same time because the logic is more compartmentalized and you
don't have to read nearly as much code to solve the issue.

------
mcphage
I love reading these articles that start with “everything that most
programmers have been doing to write software for 30 years is so obviously bad
that I don’t even need to bother supporting this argument”

~~~
naikrovek
When this article came out a few years ago, I reacted as you did. Whatever
number of years of experience I've gained since then has taught me, with
extreme clarity, that the author is correct about object oriented programming.

~~~
archagon
I've certainly learned a lot from the game programmer crowd, and I often find
myself agreeing with the anti-OO sentiment these days, but why do they have to
be so freaking _smug_ about their favorite techniques? I don't see this kind
of sneering prose nearly as often in other programming domains. It pays to be
nice, FFS!

I wholeheartedly agree with the contents of the article, but I have to hold my
nose while reading it.

~~~
mcphage
> why do they have to be so freaking smug about their favorite techniques?

Because they haven't yet spent 30 years watching those techniques being used
successfully only to read that, in fact, they obviously don't work at all.

------
lotyrin
I wonder about his distaste for "refactoring" the term and the concept, since
this seems to be pretty in-line with what I understand it to be.

Obviously plenty of architecture astronauts and cargo cults "refactor" their
stuff and produce piles of SpaghettiOs (still spaghetti, but in nice little
modules), but that's a straw man, isn't it?

~~~
hinkley
Did you come up with spaghettiOs or did you get that somewhere? You found one
I hadn’t heard before.

~~~
0xcde4c3db
The term I usually see for that is "ravioli code".

------
zamalek
I'm a big fan of passing fewer parameters in favor of a single struct - I'm
glad that Casey unintentionally demonstrated the benefits of this.
Panel_Layout can now be passed around by-ref in the event that this UI becomes
large enough that it would warrant a few methods to build it.

~~~
uryga
I've been thinking about this recently. I like passing a struct if all/most of
its attributes are used. But if the struct has, say, six attributes, and the
function uses only two, it might be clearer if the function only took those
two as parameters... While it might not be the most ergonomic solution, I
think there's something to be said for clearly marking which parts of the
struct are actually used in a function.

~~~
AlexCoventry
In languages with destructuring syntax, you get the best of both worlds.

~~~
jstimpfle
How so? It's just a syntax. It doesn't remove the physical coupling of
elements that are infrequently used as a unit.

~~~
uryga
You're right, but it can still make it obvious to the reader that you don't
_actually_ use all of the struct in a function. I think GP meant something
like this: (Haskell syntax)

    
    
      -- struct with three fields 
      data Bar = Bar { x :: Int
                     , y :: Int
                     , z :: String
                     }
    
      -- function from Bar to Baz
      foo :: Bar -> Baz
      foo (Bar _ _ z) = ...
    

`foo` takes a whole `Bar`, but in the pattern matching bit you explicitly say
you don't need x and y by using `_`.

Also, by enabling an extension[0], you can instead do:

    
    
      foo :: Bar -> Baz
      foo (Bar {z}) = ...
    

Which I guess gets pretty close to what I want.

[0] NamedFieldPuns

~~~
AlexCoventry
Yeah, that's what I meant, especially the second example, which is closer to
my experience from clojure.

------
hokus
I like a mental model like a real world factory storage: If you have few kinds
of objects you just go with random placement. If you end up looking for things
you organize them alphabetically. When that gets to annoying you number the
locations and keep a list of what is where. If the list gets confusing in turn
you split it by type of component or product. Eventually you use search engine
returning a building and coordinates.

Each of these is great until it isn't. The real magic is in anticipating what
you will need and making the switch from one to the next structure.

Who knows, it might one day be possible to have the same code displayed as
either:

give john a cookie give jack a cookie give sam a cookie give tina a cookie

and

giveCookies(john, jack, sam, tina)

and

giveCookies(testSubjects.living)

Only visually depending on the number of living test subjects without the
underlying code changing at all.

How we are to accomplish this I leave as an exercise for the reader.

------
ThJ
He talks smack about OOP but launches into talking about his latest code
project instead of explaining why it's bad. This guy would presumably also
hate relational databases, since you have to think in a similar way in order
to design those.

~~~
lucio
Hmmm... relational databases are akin to the way OP thinks, also relational
databases have an "impedance" BIG problem with OOP, which leads to BAD places.
[https://blog.codinghorror.com/object-relational-mapping-
is-t...](https://blog.codinghorror.com/object-relational-mapping-is-the-
vietnam-of-computer-science/)

------
Ace17
class-oriented programming and object-oriented programming are not the same
thing, and they don't serve the same purpose.

Class-oriented programming is used to define new types, like std::vector for
example, whose caller know about the existence. This is where the coupling
between data/logic happens.

Object-oriented programming is all about interfaces (abstract classes) and
tell-don't-asks (in one word: 'messages'), and is a tool to define boundaries
between modules.

The author seems to rant about class-orientation. Let's not throw the baby
with the bath water.

------
groby_b
"OOP is a load of horseshit"

"Well, OK, if you do it this way it kinda works. But design, design is
absolute horseshit"

Give it another decade or two, and maybe he'll encounter a code base that
justifies using OO design as well, and he'll write a new article (on how OOD
is horseshit, except when you do it his way :).

It's almost as if you choose different tools for different purposes.

~~~
SmooL
I took it more as "the promise of OOP is horseshit"

------
cgijoe
This article is from 2014. The title needs a (2014) label added.

------
fovc
This reminded me of pg's Programming Bottom Up
([http://www.paulgraham.com/progbot.html](http://www.paulgraham.com/progbot.html))

 _Language and program evolve together. Like the border between two warring
states, the boundary between language and program is drawn and redrawn, until
eventually it comes to rest along the mountains and rivers, the natural
frontiers of your problem. In the end your program will look as if the
language had been designed for it. And when language and program fit one
another well, you end up with code which is clear, small, and efficient._

Obviously, as pg points out later on, this is much easier to do in lisp, but
that doesn't preclude you from using this style in other languages

------
zaarn
I love this and I can't wait until my manager announces we'll be doing
compression-oriented programming. Which means atleast 8 meetings about how to
use Visio to model business processes and map that to Java classes. But with
compression this time.

------
nurettin
This has been posted on HN multiple times before, invoking little discussion
if any.

Author does nothing of interest. Writing lots of boilerplate and then figuring
out how to reduce it seems wasteful. And calling the alternative to his
approach OOP would be a false dichotomy.

You can do the same with much less mucking around with boilerplate by creating
data classes first and business logic classes later.

In Delphi you have best of both worlds. You can create a form and when you
inherit from it, you can re-arrange all the UI elements and add more to your
liking. If inheritance means "I want to reuse these properties" OOP works
well.

~~~
SmooL
"Writing lots of boilerplate and then figuring out how to reduce it seems
wasteful." "You can do the same with much less mucking around with boilerplate
by creating data classes first and business logic classes later."

That's exactly what the author is trying to argue against. The authors point
is that because business logic changes, and that because you can't always be
omniscient, it's hard to write the correct abstractions the first time. So
although it sounds wasteful to write boiler plate and then abstract, it's less
wasteful than abstracting, then coding, and then later having to change it all
because you got it wrong.

------
AlexCoventry
I think he's demonstrating some important coding skills, but the changes he
makes are very local, and it's also important to think about overall structure
and interaction between program components The methods he's ridiculing have
some utility for that kind of work.

------
dwaltrip
Isn't the PanelLayout essentially acting like an object?

And they already have a widely used term for compressibility in code. It's
called "DRY".

