The long way through Software Craftsmanship

A legacy code introduction

Feb 21, 2015 - 2 minute read - Comments - quotehypothesisclean-codeuncle-bobrobert-c-martinlegacy-codetiger-team

This is one of the best legacy code introductions I’ve seen:

The Grand Redesign in the Sky

Eventually the team rebels. They inform management that they cannot continue to develop in this odious code base. They demand a redesign. Management does not want to expend the resources on a whole new redesign of the project, but they cannot deny that productivity is terrible. Eventually they bend to the demands of the developers and authorize the grand redesign in the sky.

A new tiger team is selected. Everyone wants to be on this team because it’s a greenfield project. They get to start over and create something truly beautiful. But only the best and brightest are chosen for the tiger team. Everyone else must continue to maintain the current system.

Now the two teams are in a race. The tiger team must build a new system that does everything that the old system does. Not only that, they have to keep up with the changes that are continuously being made to the old system. Management will not replace the old system until the new system can do everything that the old system does.

This race can go on for a very long time. I’ve seen it take 10 years. And by the time it’s done, the original members of the tiger team are long gone, and the current members are demanding that the new system be redesigned because it’s such a mess.

Robert C. Martin in the chapter 1: Clean Code from the book by the same name

Also, why should you estimate the new tiger team abilities better than the old tiger team? Is it because the language, tools, or just because they are “plain better”?

What guarantees that the resulting software is going to be better than the old one?

Another interesting definition of legacy code is Michael Feather’s one (code without tests).

The use of power tools

Feb 18, 2015 - 6 minute read - Comments - power-toolsapprenticeship-patternschoose-your-own-adventurebig-o-notationalgorithmprotipright-tool-for-the-right-jobunix-tools

I’m currently reading the Apprenticeship patterns book, out of order (explained here: TODO).

I’m writing down the read chapters in a text file, to measure progress and also be able to backtrack if necessary. This also makes reading the book a “choose your own adventure”

After reading approximately half the chapters, the navigation wasn’t so easy using only the “see also” part. So I decided to break free from that constraint and start reading other chapters. But how do you know which chapters you have left to read? Knowing the whole set (all) and the read set (read) this is just the all - read.

Coming to a more practical way, how to know this is an automated (non-manual) way? There are m in read and n in all, where m <= n.

The simplest approach would be:

for each current in read:
  remove current from all

as read is is no particular order, that would yield some O(m*n), worst case scenario (m==n), O(n^2).

That is quite expensive, especially if you have to do it manually

If we use the same algorithm but sort the read set (no longer a set, as sets have no order). Also, converting it to a O(1) lookup table (e.g., a map), that would yield some O(n log2 n + m) that is already better. Taking into account that the sorting can be automated by the computer, it would yield a “manual O notation cost” of O(1 + m). So, relative to the amount of chapters you have read.

But we can even do better in terms of this “manual big o notation”:

read <- sort read into a map ; cost O(1)
all <- sort all into a map ; cost O(1)

unread <- all - intersection(all, read) ; cost O(1)

And this is where the power tools come into place: if we use comm or diff, the computer will create the unread set for us, in “manual” cost of O(1)

Example using vim, sort and diff

This is the read set (for the moment):

the long road
draw your own map
find mentors
the deep end
create feedback loops
the white belt
practice, practice, practice
concrete skills
your first language
use the source
reflect as you work
record what you learn
kindred spirits
nurture your passion
study the classics
expose your ignorance
dig deeper
be the worst
rubbing elbows
unleash your enthusiasm

and this is the all set (copy-paste from the book):

INTRODUCTION 1 What Is Software Craftsmanship? 3 What Is Apprenticeship? 8 What Is an Apprenticeship Pattern? 9 Where Did the Patterns Come From? 9 Where Do We Go from Here? 10
2 EMPTYING THE CUP 11 Your First Language 13 The White Belt 18 Unleash Your Enthusiasm 22 Concrete Skills 24 Expose Your Ignorance 25 Confront Your Ignorance 28 The Deep End 30 Retreat into Competence 32 Wrapping Up 34
3 WALKING THE LONG ROAD 37 The Long Road 38 Craft over Art 40 Sustainable Motivations 43 Nurture Your Passion 45 Draw Your Own Map 47 Use Your Title 50 Stay in the Trenches 52 A Different Road 53 Wrapping Up 55
4 ACCURATE SELF-ASSESSMENT 57 Be the Worst 58 Find Mentors 61 Kindred Spirits 64 Rubbing Elbows 66 Sweep the Floor 68 Wrapping Up 71
5 PERPETUAL LEARNING 73 Expand Your Bandwidth 74 Practice, Practice, Practice 77 Breakable Toys 79 Use the Source 82 Reflect As You Work 85 Record What You Learn 87 Share What You Learn 89 Create Feedback Loops 91 Learn How You Fail 94 Wrapping Up 95
6 CONSTRUCT YOUR CURRICULUM 99 Reading List 100 Read Constantly 102 Study the Classics 104 Dig Deeper 105 Familiar Tools 109 Wrapping Up 111

The first line is not interesting to our purposes, so delete it with:

go to first line (1G), then delete (dd)

After a quick inspection, there’s a number at the end of the desired line, so replace it with newline:

%s/\d\+/\r/g (a snippet below):

EMPTYING THE CUP 
 Your First Language
 The White Belt 
 Unleash Your Enthusiasm 
 Concrete Skills 
 Expose Your Ignorance
 Confront Your Ignorance 
 The Deep End 
 Retreat into Competence 
 Wrapping Up 


 WALKING THE LONG ROAD 

The title lines are all uppercase, so delete them with :%g/^\s*\u\u/d:

 Your First Language 
 The White Belt 
 Unleash Your Enthusiasm
 Concrete Skills 
 Expose Your Ignorance
 Confront Your Ignorance
 The Deep End
 Retreat into Competence
 Wrapping Up 
 
 
 The Long Road 

explanation:

  • : : command
  • % : in all the file
  • g : do (I remember it as ‘go’)
  • ^ : starting at the beginning
  • \s*: whitespace, as much a possible
  • \u\u: exactly two uppercase letters. Can also be expressed as \u\{2}
  • d : delete

for more information on vim’s regex, go here

but there are empty lines. Delete them with: %g/^$/d:

 Your First Language
 The White Belt
 Unleash Your Enthusiasm
 Concrete Skills
 Expose Your Ignorance 
 Confront Your Ignorance
 The Deep End 
 Retreat into Competence
 The Long Road

there is a space at the beginning of the line, delete it with :%s/^ //:

Your First Language 
The White Belt 
Unleash Your Enthusiasm 
Concrete Skills 
Expose Your Ignorance  
Confront Your Ignorance 
The Deep End  
Retreat into Competence 
Wrapping Up  
The Long Road  

there are upper and lowercase letters. You could find a way of doing it with vi, but I prefer something that I can remember: save the document, then process it with awk and sort

cat all.txt | awk '{print tolower($0)'}| sort > all_sorted.txt

(snippet):

a different road 
be the worst 
breakable toys 
concrete skills 
confront your ignorance 

If needed, sort and downcase the read.txt too.

cat read.txt | awk '{print tolower($0)'}| sort > read_sorted.txt

I tried using comm, but it wasn’t so useful (because of whitespace).

Tried diff:

diff read_sorted.txt all_sorted.txt  -bBw > to_read.txt

0a1
> a different road 
1a3
> breakable toys 
2a5,6
> confront your ignorance 
> craft over art 
5a10
> expand your bandwidth 
6a12
> familiar tools 
8a15

to know which are the remain chapters:

cat to_read.txt | grep ">"

to count the number of remaining chapters:

cat to_read.txt | grep ">" | wc -l

The lesson learned here is to master your tools. This would have cost me a few minutes if done manually as the list was short, too much time if long (>1000 lines).

On a funny note, it has taken me approximately 2 min to do this processing but ~45 minutes to write this blog post. So I don’t recommend you write as many posts as processings you do.

To quote Apprenticeship patterns, A different road:

If you walk away from software development, you will find that the habit of rigorous thinking and automating tasks involving large volumes of data will still be useful wherever you go

D Hoover, A Oshineye

Open discussion: Behaviour-Driven Development

Feb 15, 2015 - 2 minute read - Comments - bddopen-discussionbehaviour-driven-developmentjbehavetraining

This week we had a great discussion about Behavior Driven Development (BDD). We have explained it as a way of developing software based on requirements, via automatically tested specifications. For more information, see the wikipedia’s article on the subject

I forgot to mention that this is the perfect start to TDD, as this is usually called the double-loop TDD. See a post on it on coding is like cooking

In this double-loop TDD, the first thing is to create a BDD scenario, run it (red-1), create a unit test that reflects this red (red-2), pass it, refactor; go to red-1 as many times as you need, doing TDD cycles. When you think the feature is done, execute the BDD scenarios and go to green (outer layer) and refactor.

(Our) Common setting

Going back to BDD, a common scenario would be the following:

Layers of software:

  • Domain-Specific Language (DSL). See wikipedia’s article
  • Test adapter: an interpreter for this DSL
  • Test software: test fixtures, methods, structures to arrange, act, and assert on the sut
  • Production software (system under test - SUT): thing being tested

A BDD test vs A TDD test

Let’s imagine a BDD test for a linked list:

Given I have an empty list
When I add an element
Then I have an element on the list

now, the same test in TDD [using java, junit 4, hamcrest]

@Test
public void add_an_element_to_an_empty_list(){
	MyLinkedList linkedList = new MyLinkedList();

	linkedList.add("something");

	assertThat(linkedList.size(), is(1));
}

In some aspects, a BDD and a TDD test are similar:

  • the given is the arrange, i.e., the prerequisite
  • the when is the act, i.e., the command
  • the then is the assertion, i.e., the postcondition

(for more information on this, see Hoare’s triple)

But in others, they are not. In BDD you do not specify the APIs, methods, etc. You only care about behavior.

Conclusion

Benefits:

  • everyone might involved in the specification by example workshops (source: ATDD by example)
  • live specifications. managers can now understand the real state
  • regression tests are much cheaper (from automation)

Gotchas:

  • Test only the happy paths
  • This has a cost, do not overdo it
  • Doesn’t remove manual tests
  • How do you manage multiple scenarios
  • How fast should it be?

Implementing BDD at a client

Feb 9, 2015 - 1 minute read - Comments - bddgrunt-jobbehavior-driven-developmentsweep-the-floorapprenticeship-patternsjbehaveretrospective

This was a low-hanging fruit as a team member who specialises in QA complained about testing in the last moment during the last sprint’s retrospective.

Did the grunt job of connecting the dots and configuring the maven project (using jbehave). Also, got the inspiration from a tutorial.

Announced it only as it was in place and QA approved of it

This grunt job clicked with Sweep the floor

Let’s see how the sprint goes and what are the pain points during this sprint

Open discussion: On code reviews

Feb 7, 2015 - 3 minute read - Comments - internal-trainingopen-discussioncode-reviewpair-programmingtraining

At a client, I organized an open discussion on code reviews. We had a great conversation.

The main idea was to discuss about it and share the ideas each one had. I didn’t want it to turn into a masterclass (see the white belt)

Benefits

These are the main benefits we saw in it:

  • Increased trust
  • Learning from others, other approaches
  • Less defects, more quality
  • Increased bus factor, decreased information silos
  • Also:
    • Getting out of your comfort zone
    • Communicating more often (code style, edge cases, complaining, etc)

Pair programming

Then we discussed about the topic of code reviews and pair programming:

  • How do they mix

    • Is the need for code review reduced when doing pair programming?
    • It is cheaper to catch defects when pairing than code review (e.g., less to modify, mental caches are hot, …), so why do code reviews? J. B. Rainsberger has an article about it
  • Does it give you the same benefits?

    • I argued that it does, some of my colleagues argued against as one is “while doing” and the other is after.

Practice, Practice, Practice

This is also a reference to a chapter by the same name (here)

We proposed this problem:

Receive a list of numbers to a command-line (CLI) application and print their sum

I wrote simple code listing and we reviewed it. The code is here as a gist

(Just in case, I wrote this listing with some defects / smells on purpose)

Here are the comments:

  • Not all parameters will be added, only the first three

  • The parameters are out of order, overcomplicating things. Is it due to something? Should I be careful about it?

  • There is duplication (i.e., parsing from string)

  • Bad naming: what is a, b, c?

  • There are no tests for it. No manual / javadoc either. Therefore, it’s difficult to maintain

  • Difficult to test: a smell for bad design?

    • How to test the adding by itself? The output is to the console, so we have to capture it (at GMaur we published this tool: legacyUtils)
    • How to test the parsing if there is no mock to be injected? Only via state tests, therefore “end to end” tests as it includes the adding
  • Mixed concerns / responsibilities. Parsing the numbers and adding them are different concerns and should not be together

Conclusion

  • No one was against it
  • We all agreed that is important to do it even in time-constrained environments
  • It is also important to review our code reviews to make the most of it. The article by J. B. Rainsberger is quite useful for that
  • Even small codes can be bad and need to be reviewed (as the example)
  • Quick and dirty proof of concept do not mix well with code reviews

Pairing with junior developers

Feb 3, 2015 - 2 minute read - Comments - pairingpair-programmingexpertisejuniorseniorexperienceapprenticeship

After reading this blog post, here are my thoughts:

WARNING: the post was about how to do it, these reflections are on a more philosophical level

This is a controversial topic, as:

  • You cannot discern how much or little the other person knows more than you. I cannot find the reference anymore, but it was a to the tune of “once the other person’s level is higher than yours, you cannot know how much”
  • There are different knowledge areas. Yours and theirs might overlap on some areas, but not completely. So they may be experts on an area that is not useful to the technology you’re currently using.
  • Different people have different passions and motivators.

When and where are you a junior and a senior?

  • Does it depend on each job?
  • Is it on each product you work?
  • Is it on each team?

“when you join a new project you are starting from square one”

D. Hoover, A. Oshineye in the chapter Sweep the floor, Apprenticeship patterns

Related to the amount of senior people, is there only one senior per team?

  • Can everybody be a senior? If we assert this is true, what about “if everything matters, nothing matters”. Does that mean that everyone is senior or there are different levels of seniority and we call “the senior” the one on the top of the list?
  • Who choses the senior within the team? Is it self-organized, self-chosen? Do the people chose one? Is a shared responsibility, as each one masters a (possibly different) subject?

Food for thought.

What do you think about it?