On Second Thought

Posted by Jake Corn on February 3, 2020

Ever heard any of these? I've probably said a few myself. What follows is to flesh out some ideas.

Save it for runtime!

If something can be achieved at design time but we save it for runtime we wound our ability to benefit from static analysis. Whether using the "Pluggable Selector" pattern or dynamically loading classes/functions at runtime, or even generating alphabet characters from char codes, the upside better be worth the downside. (frequently, letting your compiler fail early is better than letting your program fail late). Though there might be a slight uptick in amount of code, often it's worth it to go ahead and type out that alphabet, or import that class, create a class for that new method. Does anyone really enjoy debugging meta-programming? Inspectability can save time even if it uses more characters. (Saving time in production maintenance is more important that in development as software begins it's life upon release).

Don't write tests! If so, write very high level ones. They are the ones that give us real confidence.

"Real programmers have confidence in their code. Tests should only cover what the customer sees. That is why we write tests...."

The truth is we write tests for many reasons. Sometimes we want confidence. Sometimes we want design -- (brilliantly, Uncle Bob said somewhere that the first clients of our production code can be our test code). Sometimes we want exploration - as in a learning test.

There are many kinds of testing. There are low level tests that test small pieces of logic. There are learning tests when we integrate 3rd party libraries into our application. There are higher level tests that crawl through your entire system replicating user flows. There are manual tests too that are best when performed by QA professionals - things like exploratory testing.

Small tests have deterministic boundaries for failure conditions. Meaning that if you have a lot of small tests, when one breaks the failure is more likely localized to the failure specifically and not an arcane message that will take hours to debug. The conventional wisdom says adhere to the "Testing Pyramid".

Object Oriented Software is obsolete.

Maybe not. I found this interesting quote from Alan Kay - creator of the Smalltalk programming language and the man who coined the term "Object Oriented".

"OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things. It can be done in Smalltalk and in LISP. There are possibly other systems in which this is possible, but I'm not aware of them."


Yes, he says that LISP is OO. For those unfamiliar with LISP it is a whole collection of functional prefix languages (In fact, lisp is one of the oldest languages still in use). There is a dialect - "Scheme" - that JavaScript was based upon before NetScape execs asked that it "look more like Java" (this was the 90s).

Ways that Functional Programming is like Object Oriented...

Local Retention and Hiding of State Process can be done via classes/clojures

Late binding can be achieved by passing pointers as either classes (OO) or functions (FP).

Messaging? Think Ruby responds_to? method (OO). Think mailboxes in Erlang. (FP)

There are other things we've learned from object technologies. SOLID is a great one that applies across programming discipline.

Programmers Write abstractions!

Yes, that's part of the job description but there are other factors. It is worth while to exercise some restraint. Often it is too early for the abstraction to exist. (IE, let some repetition build up and become a motivator for design). Testing trumps this judgement, of course. If testing without the abstraction is too difficult or too high level, then it is not too early. Good abstraction keeps software malleable without becoming volatile. Poor abstraction makes it hard to change/understand/test - among other things.

It might be better to think about it in terms of the heuristic. Inline logic is more often "DRYd" up than premature abstraction is inlined or retired for the mere fact that it is easy to know that no clients are broken.

Functional Programming is Just a Fad!

...that predates Object Oriented and Procedural Programming...

Functional Programming is defined by three values.

  1. Pure Functions - given an input (or set of) a pure function will always return the same output(s)
  2. Referential Transparency - a function may be replaced with the value of its body without changing the result of its call (programming by replacement SICP)
  3. Immutability - once values are set they will be never be changed. producing new calculations involves creating new values.

If you don't think FP can create highly reliable/testable programs, try it now. It can be done in nearly any technology and is being done more all the time.

DRY all code. All repetition is evil.

Is it evil all the time though? If a system is so simple it can be extended using copy paste, why shouldn't we use this provably valuable tool? (Will we ever go back and pay for our crimes ;) )

Know the Framework...

Does reliance on the framework create good architecture? How far does one have to buy in? Do we have to know all the parts to use any of the parts?

Interface Segregation only applies to Statically Typed languages.

Agreed. Dynamic languages (or optimistically typed languages as Kent Beck puts it) can benefit from ISP as well. In other words, even if your compiler is not forcing you to a certain interface, it's still worth while to make sure that you don't design functions/classes that use more than they have to. Doing so can increase the volatility of your system. Ever had a breaking change in a package for which you're only using a few functions? Wouldn't it have been nicer if instead of installing the whole thing you could've just had the few functions you wanted? Either way (IMO), it's forcing clients into transitive dependency they didn't know they were asking for.

Get it done and go home. Life is about more than programming.


-- jake