The long way through Software Craftsmanship

Practical Object-Oriented Design in Ruby: Chapter 2

Jul 12, 2015 - 1 minute read - Comments - reading-clubaprendiceschapterpoodrsandi-metzmartin-fowlerrubyobject-oriented-designblikikent-beck

We’ve read the second chapter from the Practical Object-Oriented Design in Ruby, by Sandi Metz.

These are the concepts and links brought up during the discussion:

Quote: Organizing Code to Allow for Easy Changes

Jul 8, 2015 - 2 minute read - Comments - poodrsandi-metztrue-codechange-codequoteeasy-changetransparentreasonableusableexemplarydesignoodooobject-oriented-designobject-oriented

Organizing Code to Allow for Easy Changes

Asserting that code should be easy to change is akin to stating that children should be polite; the statement is impossible to disagree with yet it in no way helps a parent raise an agreeable child. The idea of easy is too broad; you need concrete definitions of easiness and specific criteria by which to judge code. If you define easy to change as

  • Changes have no unexpected side effects
  • Small changes in requirements require correspondingly small changes in code
  • Existing code is easy to reuse
  • The easiest way to make a change is to add code that in itself is easy to change

Then the code you write should have the following qualities. Code should be:

  • Transparent The consequences of change should be obvious in the code that is changing and in distant code that relies upon it
  • Reasonable The cost of any change should be proportional to the benefits the change achieves
  • Usable Existing code should be usable in new and unexpected contexts
  • Exemplary The code itself should encourage those who change it to perpetuate these qualities

Code that is Transparent, Reasonable, Usable, and Exemplary (TRUE) not only meets today’s needs but can also be changed to meet the needs of the future. The first step in creating code that is TRUE is to ensure that each class has a single, well-defined responsibility.

Practical Object Oriented Design in Ruby, by Sandi Metz

This can be found the in POODR > Chapter 2. Designing Classes with a Single Responsibility > Organizing Code to Allow for Easy Changes

Note: Bold is mine

Tip: massively reverting local changes

Jul 8, 2015 - 1 minute read - Comments - sampletipgitbashregexpolish-your-toolsautomation

I was changing a massive amount of files (>1000) for a repeated code. The search and replace query was not too exact and it broke many tests in the system. For that, I preferred reverting those tests.

Here’s how to do it automatically:

Copy all the failing tests to a text editor:

Input:

testSearchXMLDocument(io.company.controller.dms.DocumentControllerTest)
testCreateXMLDocument(io.company.controller.dms.DocumentControllerTest)
testUpdateXFPageMetadata(io.company.controller.dms.DocumentControllerTest)
testCreateDocumentCrop(io.company.controller.dms.DocumentControllerTest)
testUpdateCropMetadata(io.company.controller.dms.DocumentControllerTest)
testDeleteDocument(io.company.controller.dms.DocumentControllerTest)
testUpdateXmlDocumentMetadata(io.company.controller.dms.DocumentControllerTest)
testUpdateXML(io.company.controller.dms.DocumentControllerTest)
testSearchXFPage(io.company.controller.dms.DocumentControllerTest)
testCreateXFPage(io.company.controller.dms.DocumentControllerTest)
testUpdatePage(io.company.controller.dms.DocumentControllerTest)
testSearchCrop(io.company.controller.dms.DocumentControllerTest)
testUpdateCrop(io.company.controller.dms.DocumentControllerTest)
testMoveDocument(io.company.controller.dms.DocumentControllerTest)
testGetDocument(io.company.controller.dms.DocumentControllerTest)

regex:

(tested in Sublime 3, build 3083, Windows 64)

find what: ^[^(]+\([a-Z.]*\.(.*)\)

replace with: $1

Regex explanation for ^[^(]+\([a-Z.]*\.(.*)\):

  • ^: beginning of line
  • [^(]+: every character except parenthesis, one or more times
  • \([a-Z.]*: start with one parenthesis, any number of a-z, A-Z
  • `.``: a dot, as I’m using regex replacement
  • (.*): any character, zero or more times, captured in group $1
  • \): closing parenthesis

Output:

DocumentControllerTest
DocumentControllerTest
DocumentControllerTest
DocumentControllerTest
DocumentControllerTest
DocumentControllerTest
DocumentControllerTest
DocumentControllerTest
DocumentControllerTest
DocumentControllerTest
DocumentControllerTest
DocumentControllerTest
DocumentControllerTest
DocumentControllerTest
DocumentControllerTest

copy that to file a.txt

Revert all the changes in these files:

for i in $(cat a.txt | uniq); do
  git checkout -- *$i*
done

Tip: committing to the repo file by file

Jul 8, 2015 - 1 minute read - Comments - tipprotipgitbashpolish-your-toolsautomation

I was prefer committing to the repo with commits that are as small as possible as long as it makes sense. It makes it much easier to rever the changes.

This is why I have some scripts to commit all the changes, even with the same message. This is one of them:

for f in $(git status -s |grep "^M"|awk '{print $2}'); do
  git add $f
  git commit -m "generic commit for all files"
done

Paper: Fundamental concepts on programming languages

Jul 6, 2015 - 8 minute read - Comments - christopher-stracheyprogramming-languagetheory1967coursefundamental-conceptspaperlecture

Note: all quotes on this post come from this paper: Strachey, C. Fundamental Concepts in Programming Languages. Published in Higher-Order and Symbolic Computation, 13, 11–49, 2000.

Contents

This paper starts slow, from the mathematical and philosophical point of view, until it gets to the basic concepts on the fundamental concepts:

  • Assignment command
  • L-Value and R-Value
  • Definitions
  • Names
  • Numerals
  • Conceptual models: an explanation about the relationship between the code, the memory store and the abstract concepts

Later, it gets more in depth to the conceptual constructs, where most of the content is explained and contains:

  • Expressions and commands
  • Expressions and evaluations
  • Commands and sequencing
  • Definition of functions and routines
  • Functions and routines as data items
  • Types and polymorphism
  • Compound data structures

Finally, as closing notes, it explains some implementation details (such as Load-Update Pairs), tools as Macrogenerators (nowadays called macros) and formal semantics

Notes / highlights

L-Values and R-Values

L-value for the address-like object appropriate on the left of the assignment, and R-value for the contents-like object appropriate for the right

2.1, Assignment commands in page 14

An L-value represents an area of the store of the computer. […] Two essential features […] it has content –i.e., an associated R-value– and that it is in general possible to change this content

2.2, L-values and R-Values in pages 14-15

Referential transparency

Explained in 3.2.1, Values:

In essence, this means that if we wish to find the value of an expression with contains a sub-expression, the only thing we need to know about the sub-expression is its value.

Also cites Quine 1 on this matter.

We tend to assume automatically that the symbol x in an expression such as 3x**2 + 2x + 17 stands for the same thing (or has the same value) on each occasion it occurs. This is the most important consequence of referential transparency

3.3.1 Variables, page 22

If we consider L-values as well as R-Values, however, we can preserve referential transparency as far as L-values are concerned. Thi is because L-values, being generalised addresses, are not altered by assignment command

3.3.1 Variables, page 22

Types of variables: bound, free

Explains the types of variables, based on their belonging to an environment or not: bound variable and free variable. Page 20

Evaluating vs applying

Distinction between evaluating an operator and applying it to its operands 3.2.4, Evaluation, page 20

This also introduces the concept of currification / currying:

[…] for reducing operators with several operands to the successive application of single operands operators 3.2.4, Evaluation, page 21

An example is given.

Conditional expressions vs conditional commands

Introduces the concept of conditional expression, akin to the ternary operator (example in java):

y = x > 1 ? 1 : 2;

this is equivalent to (example in java):

int y;
if(x > 1) {
	y = 1;
} else {
	y = 2;
}

and the conditional command (example in java):

if (x > 1) {
	f();
	h(x);
} else {
	g();
}

The conditional expression is also known as “functional if”

Parameter calling modes

Explains call by value and call by reference, equivalent to calling by R-Value or L-Value, respectively

3.4.2, Parameter calling mode

Functions and routines

Functions and routines are as different in their nature as expressions and commands. It is unfortunate, therefore, that most programming languages manage to confuse them very successfully

3.4.5 Functions and routines, page 30

The problem arises because we naturally expect referential transparency of R-values in expressions, particularly those on the right of assignment commands

3.4.5 Functions and routines, page 30

Any departure of R-value referential transparency in a R-value context should either be eliminated by decomposing the expression into several commands and simpler expressions, or, if this turns out to be difficult, the subject of a comment

3.4.5 Functions and routines, page 30

Constancy and fixity

“Protection by freezing”

Constancy is thus an attribute of an L-value, and is, moreover, an invariant attribute. Thus when we create a new L-value, and in particular when we define a new quantity, we must decide whether it is a constant or a variable.

3.4.6 Constants and variables, page 30

[…] fixed function. This is defined as a function which either has no free variables, or if it has, whose free variables are all both constant and fixed.

3.4.7, Fixed and free, page 31

Note that fixity is a property of the λ-expression–i.e., a property of the R-value, while constancy is a property of the L-value.

3.4.7, Fixed and free, page 31

In general:

  • Constancy is an attribute of the L-Value
  • Fixity is an attribute of the R-Value

Both for functions and objects.

First and second class objects

A procedure, on the other hand, may only appear in another procedure call either as the operator (the most common case) or as one of the actual parameters. There are no other expressions involving procedures or whose results are procedures. Thus in a sense procedures in ALGOL are second class citizens—they always have to appear in person and can never be represented by a variable or expression

3.5.1, First and second class objects, page 32

Historically this second class status of procedures in ALGOL is probably a consequence of the view of functions taken by many mathematicians: that they are constants whose name one can always recognise.

3.5.1, First and second class objects, page 33

[…] it is remarkably difficult to stop looking on functions as second class objects

3.5.1, First and second class objects, page 33

and in particular, of functions which have functions as a result

3.5.1, First and second class objects, page 33

Closure

Thus the R-value of a function contains two parts—a rule for evaluating the expression, and an environment which supplies its free variables. An R-value of this sort will be called a closure.

3.5.2, Representation of functions, page 34

Types

There is information on types: latent vs manifest, how to determine it

We call attributes which can be determined at compile time in this way manifest; attributes that can only be determined by running the program are known as latent

3.6.2, Manifest and latent, page 36

Polymorphism

Ad-hoc vs parametric polymorphism

In ad hoc polymorphism there is no single systematic way of determining the type of the result from the type of the arguments. There may be several rules of limited extent which reduce the number of cases, but these are themselves ad hoc both in scope and content

3.6.4, Polymorphism, page 37

Parametric polymorphism:

(α ⇒ β, α list) ⇒ β list

3.6.4, Polymorphism, page 37

Collections

  • List: An ordered sequence of objects all of the same type. The number is dynamically variable.
  • Ntuple: An ordered sequence of objects all of the same type. The number is dynamically variable.
  • Set: An ordered sequence of objects all of the same type. The number is dynamically variable.
  • Bag or Coll: It consists of an unordered collection of objects all of which are of the same type and differs from a set in that repetitions are allowed

3.7.7, Other forms of structure, page 45

Also talks about “rings” (3.7.7, Other forms of structure, page 45)

Macros

macrogenerators deal with the symbols which represent the variables, values and other objects of concern to a program so that all their manipulation is performed before the final compiling

4.2, Macrogenerators, page 47

Macrogeneration seems to be particularly valuable when a semantic extension of the language is required

4.2, Macrogenerators, page 47

I believe, a proper aim for programming language designers to try to make the use of macrogenerators wholly unnecessary

4.2, Macrogenerators, page 47

funny comments

One important characteristic of mathematics is our habit of using names for things

3.3.1 Variables, page 22

if this turns out to be difficult, the subject of a comment

3.4.5 Functions and routines, page 30

Bag or Coll This is a new sort of collection for which there is, as yet, no generally accepted name.

3.7.7, Other forms of structure, page 45

Review

This has been a very interesting paper, on the foundational concepts. A more formal approach to the assignment operator, L-Values and R-Values and functions.

The part about types is very interesting, explained in simple terms and with examples.

Some of the examples are in CPL, that although an old language, it is still comprehensible. The examples or equivalences in lambda calculus are more difficult to understand (I had to read an introduction to it2, just to grab the basics)

Some concepts are a bit outdated, such as the missing object orientation (or its features) or the assembly code, but in general the contents resist the time.

Many of the concepts in programming are around L-Values and R-Values and this paper has made me realize this. Also that even if we are users of these systems, I didn’t know many formalities behind it (assignment operator, rewriting, types, type inference, polymorphism modes, polymorphism without inheritance, etc).


  1. Quine, W.V. Word and Object. New York Technology Press and Wiley, 1960 ↩︎

  2. introduction to lambda calculus, search for “A Tutorial Introduction to the Lambda Calculus” ↩︎

Iterate with index in clojure

Jul 4, 2015 - 2 minute read - Comments - sampleclojurerubyiteratelanguage-comparisonprotip

Scenario: iterate a sequence (seq) with its index

The lines have an implicit line number (starting by 1, in most editors):

[1] line1
[2] line2
[3] hello

When you read it from file to a variable, it is converted to:

("line1" "line2" "hello")

This implicit line number value is not present, therefore you need to assign them one.

In ruby, you have this construct:

array = ["A", "B", "C"]
array.each_with_index {|val, index| puts "#{val} => #{index}" }

Source

In clojure, there is a similar function:

(map-indexed (fn [idx itm] [idx itm]) '(:f :o))
; ([0 "line1"] [1 "line2"] [2 "hello"])

If you want to shift the collection to the right so it starts with 1 (for the REPL):

(def lines '("line1" "line2" "hello"))
; ("line1" "line2" "hello")

(defn shift-one [lines] 
  (cons "" lines))
(def lines (shift-one lines))
lines
; ("" "line1" "line2" "hello")

(map-indexed (fn [idx itm] [idx itm])
  lines)  
; ([0 ""] [1 "line1"] [2 "line2"] [3 "hello"])

Source, especially this one

But if you only need to get the lines at certain indexes, it is also possible to get the values directly, using map on the sequence of desired indexes:

lines
; ("" "line1" "line2" "hello")

(defn get-all [lines indexes]
  (map #(nth lines %) indexes))
(get-all lines '(1 2))
; ("line1" "line2")

(get-all lines '(1 1))
; ("line1" "line1")

Note: the original source code for this post is here