What Can Journalists
Teach Developers About
Writing Source Code?
Alistair McKinnell
@amckinnell
1974
FORTRAN
PASCAL
Assembler
;-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐ ; ; PROCEDURE SetDocType(drive,version: INTEGER; docName: Str255); ; paramSize .EQU 8 drive .EQU paramSize+8-‐2 ;word version .EQU drive-‐2 ;word, lo byte used fName .EQU version-‐4 ;long, pointer to string !
LINK A6,#-‐IOFQElSize ;allocate command block MOVE.L SP,A0 ;Point to command block MOVE.L fName(A6),IOFileName(A0) ;install file name pointer MOVE.B version+1(A6),IOFileType(A0) ;install version byte MOVE drive(A6),IODrvNum(A0) ;use the specified drive. CLR.W IOFDirIndex(A0) ;And use the given file name. _GetFileInfo ;Call OS GetInfo MOVE.L #'PNTG',IOFlUsrWds(A0) ;install file type MOVE.L #'MPNT',IOFlUsrWds+4(A0) ;install creator _SetFileInfo ;Call OS SetInfo UNLK A6 MOVE.L (SP)+, A0 ;Get return address ADD #paramSize,SP ;Pop parameters JMP (A0) ;and return. C
C++
Visual Basic
Java
Ruby on Rails
SQL
Ruby
Ruby on
Rails
XSLT
Javascript
250,000
In some sense techniques for controlling
complexity is what computer science is about.
Harold Abelson
Agenda
What Is Inverted Pyramid ?
!
Writing Source Code
Using Inverted Pyramid
What Is Inverted Pyramid ?
The inverted pyramid is a metaphor used by journalists to illustrate how information should be prioritized.
“The Lead”
The Lead
“The Body”
“The Tail”
“The Lead”
The Lead
“The Body”
“The Tail”
“The Lead”: the most
important information
“The Lead”
The Lead
“The Body”
“The Tail”
“The Lead”: the most
important information
“The Body”: the crucial
information
“The Lead”
The Lead
“The Body”
“The Tail”
“The Lead”: the most
important information
“The Body”: the crucial
information
“The Tail”: any extra
information
The Lead
Benefits for Readers
1. Readers can leave an article at any point
and understand it, even if they do not
have all the details. 2. For those readers who wish to proceed, it
conducts them through the article details.
Exercise
1
•
•
•
Arrange cards as above
1–2 groups per table 3–4 people per group
2222
Some Boos at Graduation After Judge Bars Prayer
Associated Press
May 21, 2001
WASHINGTON, Ill. - A top student who gave a traditional farewell
speech at a high school graduation was booed and another student
was applauded for holding a moment of silence after a judge barred
prayer at the ceremony.
•
•
•
•
2222
Experience inverted pyramid Read one card at a time
You have 4 minutes
It’s not important to read all cards
Some Boos at Graduation After Judge Bars Prayer
Associated Press
May 21, 2001
“The Lead”
WASHINGTON, Ill. - A top student who gave a traditional farewell speech at a high school graduation was
booed and another student was applauded for holding a moment of silence after a judge barred prayer at
the ceremony.
A federal judge issued a restraining order days before Sunday's ceremony at Washington Community
High School blocking any student-led prayer. It was the first time in the 80-year history of the school that
no graduation prayers were said.
The Lead
“The Body”
Natasha Appenheimer, the class valedictorian, traditionally a top student chosen to give the class
graduation speech, was booed when she received her diploma. Her family, backed by the American Civil
Liberties Union, had filed the lawsuit that led to the restraining order. Meanwhile, some stood and
applauded class speaker Ryan Brown when he bowed his head for a moment of silence before his
speech.
About 200 people attended a prayer vigil before the ceremony, and a placard-carrying atheist and a
Pentecostal minister got into a shouting match.
In spite of the turbulent atmosphere, Appenheimer said she wasn't upset by the way things turned out.
“The Tail”
"It's my graduation. I'm happy," she said. The lawsuit "was worth it. We changed things, we righted a
wrong and made something better than it was before. I learned that when you believe in something, you
should stand up for it."
Graduate Annie White disagreed, saying many class members wanted to demonstrate that "God was a
part of our graduation."
Superintendent Lee Edwards said the school district might appeal McDade's ruling. He said the
invocation and benediction prayers usually said at the ceremony were innocuous, and "You would have to
have been working pretty hard to be offended."
School district officials defended the prayer on grounds that students, not administrators, were in charge
of graduation.
The Supreme Court's landmark 1962 decision outlawed organized prayer in public schools. In 1992, the
justices barred clergy-led prayers at graduations, and last year, the court barred officials from letting
students lead crowds in prayer before football games.
public class StringCalculator {
!
!
!
!
!
public int add(String numbers) {
List<Integer> values = convertToInteger(parseValues(numbers));
failWhenContainsNegatives(values);
return sumOf(values);
}
private String[] parseValues(String numbers) {
if (numbers.isEmpty()) {
return new String[] {};
}
if (containsCustomDelimiters(numbers)) {
return parseCustomDelimitedValues(numbers);
}
!
!
!
!
!
}
private List<Integer> convertToInteger(String[] numbers) {
List<Integer> result = new ArrayList<>();
!
!
!
return result;
!
for (Integer value : values) {
if (value < 0) negatives.add(value);
}
!
if (!negatives.isEmpty()) {
String message = "Error: negatives not allowed " + negatives;
throw new RuntimeException(message);
}
}
}
private boolean containsCustomDelimiters(String numbers) {
return numbers.startsWith("//");
}
private String[] parseCustomDelimitedValues(String numbers) {
int newlineIndex = numbers.indexOf('\n');
String delimiters = numbers.substring(2, newlineIndex);
String numberList = numbers.substring(newlineIndex + 1);
String[] customDelimiters = parseCustomDelimiters(delimiters);
!
!
private void failWhenContainsNegatives(List<Integer> values) {
List<Integer> negatives = new ArrayList<>();
return result;
for (String number : numbers) {
result.add(toInteger(number));
}
}
for (Integer value : values) {
result += value;
}
!
return parseStandardDelimiters(numbers);
!
!
private int sumOf(List<Integer> values) {
int result = 0;
!
!
!
!
!
}
for (String customDelimiter : customDelimiters) {
numberList = numberList.replaceAll(
quoteRegularExpression(customDelimiter), ",");
}
return numberList.split(",");
}
private String[] parseCustomDelimiters(String rawCustomDelimiters) {
return rawCustomDelimiters.replaceAll("\\[", "").split("\\]");
}
private String quoteRegularExpression(String customSeparator) {
return "\\Q" + customSeparator + "\\E";
}
private String[] parseStandardDelimiters(String numbers) {
return numbers.split("[,\n]");
}
private Integer toInteger(String number) {
Integer value = Integer.parseInt(number);
return value <= 1000 ? value : 0;
}
public class
!
!
!
The Lead
!
Benefits for Readers
private
public
List<Integer> values = convertToInteger(parseValues(numbers));
!
result += value;
failWhenContainsNegatives(values);
}
}
!
!
}
1. Readers can leave an article
at any point
!
!
! if they do not
and
understand
it,
even
!
have all the details. !
!
private
private
}
}
private
}
String delimiters = numbers.substring(2, newlineIndex);
String numberList = numbers.substring(newlineIndex + 1);
}
!
String[] customDelimiters = parseCustomDelimiters(delimiters);
private
List<Integer> result =
numberList = numberList.replaceAll(
quoteRegularExpression(customDelimiter),
}
!
!
2.
For those readers who! wish to proceed, it
!
conducts
them
through
the
article
details.
!
!
result.add(toInteger(number));
}
}
}
private
private
List<Integer> negatives =
}
private
!
}
!
String message =
}
}
!
!
!
}
}
private
}
private
Integer value = Integer.parseInt(number);
}
The Lead
Benefits for Developers
1. Readers can leave an article at any point
and understand it, even if they do not
have all the details. 2. For those readers who wish to proceed, it
conducts them through the article details.
The Lead
Benefits for Developers
1. Developers can leave source code at any
point
and understand it, even if they do
not
have all the details.
2. For those readers who wish to proceed, it
conducts them through the article details.
The Lead
Benefits for Developers
1. Developers can leave source code at any
point and understand it, even if they do
not have all the details.
2. For those developers who need to see
more implementation details, it conducts
them through the source code.
The Lead
Benefits for Developers
1. Understanding without all the details
2. Details are effectively organized
Exercise
Lead
•
•
Body
Body
Body
Same groups as last exercise Arrange cards as above
Tail
Tail
Tail
int add(String numbers)
numbers
add(numbers)
“1,2,3”
6
“1,1001,2”
3
“1,-2,3,-4”
Error showing -2, -4
“//#\n2#4#6”
12
public int add(String numbers) {
List<Integer> values = convertToInteger(parseValues(numbers));
failWhenContainsNegatives(values);
return sumOf(values);
}
Body
Body
Body
Tail
Tail
Tail
•
•
Flip over the card labelled Lead
•
Share that understanding with your group
What can you say about the add()
method from reading the Lead card ?
public int add(String numbers) {
List<Integer> values = convertToInteger(parseValues(numbers));
failWhenContainsNegatives(values);
private String[] parseValues(String numbers) {
if (numbers.isEmpty()) {
return new String[] {};
}
return sumOf(values);
if (containsCustomDelimiters(numbers)) {
return parseCustomDelimitedValues(numbers);
}
}
Body
Body
return parseStandardDelimiters(numbers);
}
Tail
Tail
Tail
•
•
Flip over the Body cards one at a time
•
•
Next, flip over the Tail cards
Ask yourself: What do I notice about the
code after reading each card ?
It’s not important to read all cards
public class StringCalculator {
!
!
!
!
!
public int add(String numbers) {
List<Integer> values = convertToInteger(parseValues(numbers));
failWhenContainsNegatives(values);
return sumOf(values);
}
private String[] parseValues(String numbers) {
if (numbers.isEmpty()) {
return new String[] {};
}
if (containsCustomDelimiters(numbers)) {
return parseCustomDelimitedValues(numbers);
}
!
!
!
!
!
}
private List<Integer> convertToInteger(String[] numbers) {
List<Integer> result = new ArrayList<>();
!
!
!
return result;
!
for (Integer value : values) {
if (value < 0) negatives.add(value);
}
!
if (!negatives.isEmpty()) {
String message = "Error: negatives not allowed " + negatives;
throw new RuntimeException(message);
}
}
}
private boolean containsCustomDelimiters(String numbers) {
return numbers.startsWith("//");
}
private String[] parseCustomDelimitedValues(String numbers) {
int newlineIndex = numbers.indexOf('\n');
String delimiters = numbers.substring(2, newlineIndex);
String numberList = numbers.substring(newlineIndex + 1);
String[] customDelimiters = parseCustomDelimiters(delimiters);
!
!
private void failWhenContainsNegatives(List<Integer> values) {
List<Integer> negatives = new ArrayList<>();
return result;
for (String number : numbers) {
result.add(toInteger(number));
}
}
for (Integer value : values) {
result += value;
}
!
return parseStandardDelimiters(numbers);
!
!
private int sumOf(List<Integer> values) {
int result = 0;
!
!
!
!
!
}
for (String customDelimiter : customDelimiters) {
numberList = numberList.replaceAll(
quoteRegularExpression(customDelimiter), ",");
}
return numberList.split(",");
}
private String[] parseCustomDelimiters(String rawCustomDelimiters) {
return rawCustomDelimiters.replaceAll("\\[", "").split("\\]");
}
private String quoteRegularExpression(String customSeparator) {
return "\\Q" + customSeparator + "\\E";
}
private String[] parseStandardDelimiters(String numbers) {
return numbers.split("[,\n]");
}
private Integer toInteger(String number) {
Integer value = Integer.parseInt(number);
return value <= 1000 ? value : 0;
}
public class StringCalculator {
!
public int add(String numbers) {
List<Integer> values = convertToInteger(parseValues(numbers));
!
failWhenContainsNegatives(values);
!
return sumOf(values);
}
public class StringCalculator {
!
public int add(String numbers) {
List<Integer> values = convertToInteger(parseValues(numbers));
!
failWhenContainsNegatives(values);
!
return sumOf(values);
}
The Lead
Understanding without all the detail
Details are effectively organized
Writing Source Code
Using Inverted Pyramid
Compose Method
!
You can’t rapidly understand
a method’s logic.
!
Transform the logic into a
small number of intentionrevealing steps at the same
level of detail.
Composed Method
!
Compose methods out of
calls to other methods, each
of which is at roughly the
same level of abstraction.
Composed Method and SLAP
!
Composed method
encourages factoring (or
refactoring) code into small,
cohesive, readable chunks.
SLAP stands for the Single Level of Abstraction Principle.
Example
public int add(String numbers) {
List<Integer> negatives = new ArrayList<>();
int sum = 0;
for (String number : parseValues(numbers)) {
Integer value = Integer.parseInt(number);
if (value < 0) {
negatives.add(value);
} else if (value <= 1000) {
sum += value;
}
}
if (!negatives.isEmpty()) {
throw new RuntimeException("Error: negatives not allowed " +
negatives);
}
return sum;
}
public int add(String numbers) {
List<Integer> negatives = new ArrayList<>();
int sum = 0;
for (String number : parseValues(numbers)) {
Integer value = Integer.parseInt(number);
if (value < 0) {
negatives.add(value);
} else if (value <= 1000) {
sum += value;
}
}
if (!negatives.isEmpty()) {
throw new RuntimeException("Error: negatives not allowed " +
negatives);
}
return sum;
}
You can’t rapidly understand
a method’s logic.
public int add(String numbers) {
List<Integer> values = convertToInteger(parseValues(numbers));
!
failWhenContainsNegatives(values);
!
return sumOf(values);
}
Compose methods out of
calls to other methods, each
of which is at roughly the
same level of abstraction.
public int add(String numbers) {
List<Integer> values = convertToInteger(parseValues(numbers));
!
failWhenContainsNegatives(values);
!
return sumOf(values);
}
Understanding without all the detail
The Lead
Details are effectively organized
Example
The Lead
private String[] parseValues(String numbers) {
if (numbers.isEmpty())
return new String[] {};
!
if (numbers.startsWith("//")) {
int newlineIndex = numbers.indexOf('\n');
String delimiters = numbers.substring(2, newlineIndex);
String numberList = numbers.substring(newlineIndex + 1);
String[] customDelimiters = delimiters.
replaceAll("\\[", "").split("\\]");
for (String customDelimiter : customDelimiters) {
numberList = numberList.
replaceAll("\\Q" + customDelimiter + "\\E", ",");
}
return numberList.split(",");
}
!
return numbers.split("[,\n]");
}
private String[] parseValues(String numbers) {
if (numbers.isEmpty())
return new String[] {};
!
if (numbers.startsWith("//")) {
int newlineIndex = numbers.indexOf('\n');
String delimiters = numbers.substring(2, newlineIndex);
String numberList = numbers.substring(newlineIndex + 1);
String[] customDelimiters = delimiters.
replaceAll("\\[", "").split("\\]");
for (String customDelimiter : customDelimiters) {
numberList = numberList.
replaceAll("\\Q" + customDelimiter + "\\E", ",");
}
return numberList.split(",");
}
!
return numbers.split("[,\n]");
}
private String[] parseValues(String numbers) {
if (numbers.isEmpty())
return new String[] {};
!
if (numbers.startsWith("//")) {
return parseCustomDelimitedValues(numbers);
}
!
return numbers.split("[,\n]");
}
private String[] parseValues(String numbers) {
if (numbers.isEmpty())
return new String[] {};
!
if (numbers.startsWith("//")) {
return parseCustomDelimitedValues(numbers);
}
!
return numbers.split("[,\n]");
}
SLAP stands for the Single Level of Abstraction Principle.
private String[] parseValues(String numbers) {
if (numbers.isEmpty())
return new String[] {};
!
if (numbers.startsWith("//")) {
return parseCustomDelimitedValues(numbers);
}
!
return numbers.split("[,\n]");
}
SLAP stands for the Single Level of Abstraction Principle.
private String[] parseValues(String numbers) {
if (numbers.isEmpty())
return new String[] {};
!
if (numbers.startsWith("//")) {
return parseCustomDelimitedValues(numbers);
}
!
return numbers.split("[,\n]");
}
private String[] parseValues(String numbers) {
if (numbers.isEmpty())
return new String[] {};
!
if (containsCustomDelimiters(numbers)) {
return parseCustomDelimitedValues(numbers);
}
!
return numbers.split("[,\n]");
}
private String[] parseValues(String numbers) {
if (numbers.isEmpty())
return new String[] {};
!
if (containsCustomDelimiters(numbers)) {
return parseCustomDelimitedValues(numbers);
}
!
return parseStandardDelimiters(numbers);
}
private String[] parseValues(String numbers) {
if (numbers.isEmpty())
return new String[] {};
!
if (containsCustomDelimiters(numbers)) {
return parseCustomDelimitedValues(numbers);
}
!
return parseStandardDelimiters(numbers);
}
SLAP stands for the Single Level of Abstraction Principle.
private String[] parseValues(String numbers) {
if (numbers.isEmpty())
return new String[] {};
!
if (containsCustomDelimiters(numbers)) {
return parseCustomDelimitedValue(numbers);
}
!
return parseStandardDelimiters(numbers);
}
Understanding without all the detail
The Lead
Details are effectively organized
Applying Inverted Pyramid
The Lead
The Lead
Compose Method
Liabilities
• Can lead to an overabundance of small methods.
• Can make debugging difficult because logic is spread out across many small methods.
Refactoring to Patterns
Compose Method
Benefits
•
Efficiently communicates what a method does and how it does what it does.
•
Simplifies a method by breaking it up into well-named chunks of behaviour at the same level of detail.
Refactoring to Patterns
“The Lead”
The Lead
“The Body”
“The Tail”
The Lead
Benefits for Developers
1. Developers can leave source code at any
point and understand it, even if they do
not have all the details.
2. For those developers who need to see
more implementation details, it conducts
them through the source code.
Exercise
1
•
•
Grab an index card to write on
Write down 2 things you are going to
consider next time you write code
1
•
Take turns sharing what you wrote with
everyone at your table
•
This is optional. Unlike in kindergarten,
you don’t have to share
In some sense techniques for controlling
complexity is what computer science is about.
Harold Abelson
The Lead
Benefits for Developers
1. Understanding without all the details
2. Details are effectively organized
You know you are working on clean code
when each routine you read turns out to be
pretty much what you expected.
Ward Cunningham
Books
Refactoring to Patterns
Joshua Kerievsky
Implementation Patterns
Kent Beck
The Productive Programmer
Neal Ford
Clean Code
Robert C. Martin
Photos
www.flickr.com/photos/
ecu_digital_collections/3288382289/
www.morguefile.com/
archive/display/848917
© Copyright 2026 Paperzz