Programming,Only Better



Programming,Only Better

0 19


only-better

This project has moved:

On Github bodil / only-better

Programming,Only Better

@bodil

Edsger W. Dijkstra

Dijkstra's Algorithm

GOTO Considered Harmful

GOTO Considered Harmful

Dijkstra originally studied theoretical physics before becoming a computer scientist.

“The use of COBOL cripples the mind; its teaching should, therefore, be regarded as a criminal offence.”
“It is practically impossible to teach good programming to students that have had a prior exposure to BASIC: as potential programmers they are mentally mutilated beyond hope of regeneration.”
“[Java is] embarrassing, because it is so bad. [...]A good language, like a tool, is just a joy. But industry doesn't want that. Probably because decisions are made by technically incompetent people.”

Edsger W. Dijkstra1930–2002

“Programming is one of the most difficult branches of applied mathematics; the poorer mathematicians had better remain pure mathematicians.”

Reasoning About Software

Formal reasoning proves correctness.

Formal reasoning means maths.

Informal reasoning meansthinking about your code.

Debugging is a process of informal reasoning.

Today

2001: The Agile Manifesto

Some people would have us think code quality can be improved only through project management.

Whatever the path to great code might be, it doesn't go through project management.

Silver Bullets

  • Iterative design
  • Pair programming
  • Test Driven Development

The enthusiasm is genuine.

People are different.

Pinkie Pie

  • Likes to pair program all day!
  • Finds up front planning wasteful!
  • Finds TDD extra super tedious!

Fluttershy

  • Can't focus with others around.
  • Prefers to know where she's going.
  • Enjoys methodical TDD.

We have no idea what we're doing.

Agile is not Science.

Try it anyway. Some of it could work.

There is no Truth out there.

Agile is not Science.

Agile sees programming as a matter of process, not tools.

“Bad programmers can writebad code in any language.”

This is our industry's best effort.

What is the cause of bad code?

Complexity

Out of the Tar Pit

Moseley & Marks, 2006

Understanding Code

  • Testing
  • Informal reasoning

Informal Reasoning

“Those who want really reliable software will discover that they must find means of avoiding the majority of bugs to start with.”

Testing leads to more errors being detected.

Informal reasoning leads to less errors being created.

Testing

“testing is hopelessly inadequate … it can be used very effectively to show the presence of bugs but never to show their absence.”

Sources of Complexity

  • State
  • Control
  • Code Volume

State

            class Fac {
              public static long fac(long n) {
                return (n == 0) ? 1 : n * fac(n - 1);
              }
            }

            Fac.fac(5);

            Fac.fac(10);
          

State Spoils Testing

  • Testing a component in one state tells you nothing about the same component in another state.
  • We test it anyway because what else can you do?
  • Programs still get into a bad state.

Example Based Testing

Testing a component with one input also tells you nothing about the same component with another input.

Generative testing is a thing.

State Spoils Informal Reasoning

  • The number of possible states grows exponentially with added state.
  • You have to reason about all possible states.
  • It's hard to be sure where state changes come from.

State is the Great Evil

Control

Control is about the order in which things happen.

            var a = 2;

            var b = a + 3;

            var c = b * 2;

            c;
          

omg concurrency

  • What does the control flow of a concurrent system look like?
  • How do you test something when you can't even be sure of the order in which it happens?
  • Or when something else might be changing its state at the same time?

Code Volume

“Many of the classic problems of developing software products derive from this essential complexity and its nonlinear increase with size.”

Code Volume

“It has been suggested that there is some kind of law of nature telling us that the amount of intellectual effort needed grows with the square of program length. But, thank goodness, no one has been able to prove this law.”

Managing State with Object-Orientation

  • OOP is built around encapsulated state, but:
  • It helps you structure the code in an understandable way.
  • You can enforce internal integrity constraints.
  • Less helpful when constraints must be enforced across objects.

Encapsulating state also encapsulates surprises.

Managing Control with Object-Orientation

  • You don't.
  • OO polymorphism makes it harder if anything.

Functional Programming and State

  • Object-orientation idealises encapsulated state.
  • Functional programming idealises referential transparency.
  • Referential transparency means no state, only inputs and outputs.
  • No side effects.
            class Number {
              private long value;
              public Number(long value) {
                this.value = value;
              }
              public long get() {
                return this.value;
              }
              public void inc() {
                this.value = this.value + 1;
              }
            }

            Number n = new Number(0);

            n.inc();

            n.get();
          
            (def number {:value 0})

            (defn succ [number]
              (assoc number :value (+ (:value number) 1)))

            (succ number)
          
            datatype number = number of int;

            val n = number 0;

            fun inc (number n) = number (n+1);

            inc n;
          

Referential Transparency

  • Eliminates the problem of state when testing.
  • Still doesn't tell us anything about inputs you don't test for.
  • Because you don't worry about state, informal reasoning becomes much easier.

So Where Did the State Go?

It's still there, but it's being passed around. State is represented by values, not objects, so it can't mutate.
            class Number {
              private long number;
              public Number(long number) {
                this.number = number;
              }
              public void set(long n) {
                this.number = n;
              }
              public static void mutableStateIsBad(Number n) {
                n.set(666);
              }
              public long fac() {
                return (this.number == 0) ? 1 : this.number * new Number(this.number-1).fac();
              }
            }
          

Concurrency Still Sucks, Right?

  • No mutable state!
  • Referential transparency means parallelisation is easier.

Control in Functional Programming

  • Functional style lessens the problem of control.
  • You still have control structures.
            function fac(n) {
              if (n === 0) {
                return 1;
              } else {
                return n * fac(n - 1);
              }
            }
          
            let fac 0 = 1
                fac n = n * fac (n-1)

            fac 5

            fac 10
          
            let inclist :: [Int] -> [Int]
                inclist [] = []
                inclist (head:tail) = (head+1) : inclist tail
          

tl;dr:

  • OOP has a state abuse problem we need to stop ignoring.
  • FP is not perfect, but it mostly eliminates mutable state.
  • Complexity through control still exists in FP.

We need to talk.

            var a = 2;

            var b = a + 3;

            var c = b * 2;

            c;
          
            (let [a 2
                  b (+ a 3)
                  c (* b 2)]
              c)
          
            val a = 2;

            val b = a + 3;

            val c = b * 2;

            c;
          
            (use 'clojure.core.logic)

            (require '[clojure.core.logic.fd :refer
                       [in interval + * != distinct eq]])
          
            (run* [a b c]
              )
          

Declarative Programming Now!

An ideal language eliminates control.

It only has to deal with essential state.

You tell it what you want,it figures out how to get there.

            (use 'clojure.core.logic)

            (require '[clojure.core.logic.fd :refer
                       [in interval + != distinct eq]])
          
            (run* [a b]
              )
          
  • Modern functional languages aspire to this ideal.
  • Modern imperative languages are headed in the opposite direction.

Maybe we should prefer the onewith fewer surprises.

Thank you!

@bodil

github.com/bodil/only-better