Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
[RC Diary] Out of the tar pit (-86)

[RC Diary] Out of the tar pit (-86)

Time to think

On the way back from RC I thought about the challenges I will have to face for Cerebro in the next week:

  • only mutate sources that are covered by tests (even if for now I could assume 100% code coverage)
  • improve the usage of data structures, right now there's a lot of impedence mismatch between modules
  • solve the duplicated variable declaration

It was really productive, I've also had a couple ideas about Professor X but that's way too early.

I think I have to setup some kind of daily reminder of good activities, something like:

during the week

  • cerebro
  • project lamo
  • study groups

during the weekend

  • mock interviews
  • catchup with backlog
  • the little schemer (and hopefully at some point SICP)

The little schemer chapter 3

Started implementing rember as specified. It's taking quite some time.

More material

I've had a look at this video from LambdaConf 2016, it's helpful if you want to understand where Functional Relational Programming concepts are applied in today's UI frameworks.

Out of the tar pit notes

DISCLAIMER: read the paper, don't read my notes. These are here for my benefit.

A primary value of that paper, which I highly recommend, is the focus on complexity, and the role of state in complexity.

-- Rich Hickey (creator of Clojure)

The classic approach to solving the problem represented by state is either:

  • enclosing state in objects using object oriented programming
  • or using functional programming

Complexity as the major problem in software, due to state handling.

Goal is being able to think and reason about our systems.

Testing from the outside and informal reasoning (looking at the inside) as a way to understand a system are both faulty.

  • testing doesn't help because it covers just one possible state and you know nothing about what would happen with a different state

  • informal reasoning doesn't help because its difficult to hold in mind all the possible scenarios that are happing as consequence of dealing with state

Order and concurrency can add even more uncertainty to informal reasoning

What would you pick you had to choose between

  • testing
  • reasoning
  • simplicity

Simplicity. Because any future attempt to understand the system will work.

The following are common answers when dealing with a faulty piece of software that is not working and we need to have it in a working condition:

  • try it again
  • reload the document
  • restart the program
  • reboot your computer
  • re-install the program
  • re-install the operating system and then the program

These are all caused by state, and are all remedies trying to put the internal state back into a good situation.

It's really hard to enumerate and understand all possible states of a system

Control, intended as ordering of statements, is another source of complexity, as is code volume.

So: complexity comes from, in order of relevance: state, control, and volume

By suitable application of our powers of abstraction, the intellectual effort needed to conceive or to understand a program need not grow more than proportional to program length.

Complexity breeds complexity and it poisons adjacent parts.

Simplicity is hard.

Power corrupts: state is power, manual memory management is power (hence it's being removed).

Managing complexity

OOP

Enforce integrity contraints over state by regulating access to state via methods

Problems:

  • contraints are at single object level
  • multiple resource might ask the same thing at the same time updating it

OOP relies on state and all behaviour is related to this state, so it's not a good foundation for avoiding complexity.

FP

By avoiding state and side effects the entire system gains referential transparency property given a set of arguments the function will always behave in the same way

// no! state! bad!
let getNextCounter = () => ++counter

// while in FP you would
let getNextCounter = (oldCounter) => oldCounter + 1

The caller should make sure getNextCounter is called with the right param, passing a big object for example named state that contains all state lets us keep referential transparency but at the cost of ease of reasoning.

Functional program: you can always tell what will come out of a procedure by looking at its parameters

Stateful program -> nope.

Logic program -> removes the burden of control

Complexity

Essential - intrinsic of the problem

Accidental - all the rest (infrastructure issues, performance issues, language issues, etc)

Try to avoid as much accidental complexity as possible

Recommendation - complexity (state + control) 1: avoid, 2: separate

Declare accidental state in a completely separated infrastructure, we can then forget that accidental state even exists

Split logic from state to get

                      →      essential logic
accidental state
and control                         ↓
                                      
                       →      essential state

Relational model

Relations

  • base
  • derived - composed of other relations (base or derived)

No duplicates and no order

No need to come up with access paths beforehand, think of employees containing departments or departments containing employees (or even worse, both) as a problem that relations solve

Manipulation

Manipulating happens through the use of relational algebra:

  • restrict(r) - selection of a subset of the records in a relation according to some criteria
  • project(r) - new relation from an old one without some attributes removed from the records
  • product(r1, r2) - carthesian product
  • union(r1, r2) - creates a relation of all items from both argument relations
  • intersection(r1, r2) - creates a relations containing all items in both argument relations
  • difference(r1, r2) - create a relation containing all records in r1 but not in r2
  • join(r1, r2) - creates all possible records that result from matching identical attributes in r1 and r2
  • divide(r1, r2, r3) - returns all records of r1 occurring in r2 associated with each record in r3

Integrity

Maintained by specifying constraints that must hold at all times.

Data independence

Separating the logical model from the physical storage representation.

Functional Relational Programming

In FRP all essental state takes the form of relations, and the essential logic is expressed using relational algebra extended with pure user defined functions

FRP goal is eliminate complexity.

  • relational model specifies essential state
  • relational algebra specifies essential logic
  • observers listen on a relationship to update UI and outputs
  • accidental complexity could be specified declaratively

Resources

Plans

  • videos from Chomsky - find which ones are the best and get them
  • "check that parens are balanced" exercise
  • still need some attention needed for timsort, radix sort
  • chapter 3 of the little schemer in Clojure
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment