Presented at DevTernity (1st December 2016)
Video available at https://www.youtube.com/watch?v=SUIUZ09mnwM
Habits help you manage the complexity of code. You apply existing skill and knowledge automatically to the detail while focusing on the bigger picture. But because you acquire habits largely by imitation, and rarely question them, how do you know your habits are effective? Many of the habits that programmers have for naming, formatting, commenting and unit testing do not stand up as rational and practical on closer inspection. This talk examines seven coding habits that are not as effective as programmers believe, and suggests alternatives.
5. code, noun
a set of instructions for a computer
a computer program, or a portion thereof
a system of words, figures or symbols used to
represent others, especially for the purposes of
secrecy
a set of conventions or principles governing
behaviour or activity in a particular domain
Concise Oxford English Dictionary ∙ Oxford English Dictionary ∙ Merriam-Webster's Collegiate Dictionary
6. habit, noun
a settled or regular tendency or practice
an acquired mode of behaviour that has become
nearly or completely involuntary
bodily condition or constitution
a costume characteristic of a calling, rank, or
function
Concise Oxford English Dictionary ∙ Oxford English Dictionary ∙ Merriam-Webster's Collegiate Dictionary
16. Signal-to-noise ratio (often abbreviated SNR or
S/N) is a measure used in science and engineering
that compares the level of a desired signal to the
level of background noise.
Signal-to-noise ratio is sometimes used informally
to refer to the ratio of useful information to false or
irrelevant data in a conversation or exchange.
http://en.wikipedia.org/wiki/Signal_to_noise_ratio
17. To be, or not to be: that is the question:
Whether 'tis nobler in the mind to suffer
The slings and arrows of outrageous fortune,
Or to take arms against a sea of troubles,
And by opposing end them?
William Shakespeare
Hamlet
18. Continuing existence or cessation of
existence: those are the scenarios. Is it
more empowering mentally to work towards
an accommodation of the downsizings and
negative outcomes of adversarial
circumstance, or would it be a greater
enhancement of the bottom line to move
forwards to a challenge to our current
difficulties, and, by making a commitment
to opposition, to effect their demise?
Tom Burton
Long Words Bother Me
19. function leftpad (str, len, ch) {
str = String(str);
var i = -1;
if (!ch && ch !== 0) ch = ' ';
len = len - str.length;
while (++i < len) {
str = ch + str;
}
return str;
}
21. function leftpad(content, length, pad) {
content = String(content)
pad = String(pad || pad === 0 ? pad : ' ')[0]
var left = Math.max(length - content.length, 0)
return pad.repeat(left) + content
}
22.
23. var cache = [
'',
' ',
' ',
' ',
' ',
' ',
' ',
' ',
' ',
' '
];
function leftPad (str, len, ch) {
// convert `str` to `string`
str = str + '';
// `len` is the `pad`'s length now
len = len - str.length;
// doesn't need to pad
if (len <= 0) return str;
// `ch` defaults to `' '`
if (!ch && ch !== 0) ch = ' ';
// convert `ch` to `string`
ch = ch + '';
// cache common use cases
if (ch === ' ' && len < 10) return cache[len] + str;
// `pad` starts with an empty string
var pad = '';
// loop
while (true) {
// add `ch` to `pad` if `len` is odd
if (len & 1) pad += ch;
// divide `len` by 2, ditch the remainder
len >>= 1;
// "double" the `ch` so this operation count grows logarithmically on `len`
// each time `ch` is "doubled", the `len` would need to be "doubled" too
// similar to finding a value in binary search tree, hence O(log(n))
if (len) ch += ch;
// `len` is 0, exit the loop
else break;
}
// pad `str`!
return pad + str;
}
24.
25.
26. Comments
A delicate matter, requiring taste and judgement. I tend to err on the side of
eliminating comments, for several reasons. First, if the code is clear, and uses
good type names and variable names, it should explain itself. Second, comments
aren't checked by the compiler, so there is no guarantee they're right, especially
after the code is modified. A misleading comment can be very confusing. Third,
the issue of typography: comments clutter code.
Rob Pike, "Notes on Programming in C"
27. There is a famously bad comment style:
i=i+1; /* Add one to i */
and there are worse ways to do it:
/**********************************
* *
* Add one to i *
* *
**********************************/
i=i+1;
Don't laugh now, wait until you see it in real life.
Rob Pike, "Notes on Programming in C"
28. A common fallacy is to assume authors
of incomprehensible code will somehow
be able to express themselves lucidly
and clearly in comments.
Kevlin Henney
https://twitter.com/KevlinHenney/status/381021802941906944
31. To be, or not to be: that is the question:
Whether 'tis nobler in the mind to suffer
The slings and arrows of outrageous fortune,
Or to take arms against a sea of troubles,
And by opposing end them?
William Shakespeare
Hamlet
32. Continuing existence or cessation of
existence: those are the scenarios. Is it
more empowering mentally to work towards
an accommodation of the downsizings and
negative outcomes of adversarial
circumstance, or would it be a greater
enhancement of the bottom line to move
forwards to a challenge to our current
difficulties, and, by making a commitment
to opposition, to effect their demise?
Tom Burton
Long Words Bother Me
33. Continuing existence or cessation of existence:
those are the
more empowe
to work towa
accommodati
downsizings
outcomes of
circumstance
a greater enh
the bottom li
forwards to a
our current d
by making a
opposition, t
demise?
36. To answer the question "What is clean design?"
most succinctly: a clean design is one that
supports visual thinking so people can meet their
informational needs with a minimum of
conscious effort.
Daniel Higginbotham ∙ "Clean Up Your Mess — A Guide to Visual Design for Everyone" ∙ http://www.visualmess.com/
37. You convey information by the way you arrange
a design's elements in relation to each other. This
information is understood immediately, if not
consciously, by the people viewing your designs.
Daniel Higginbotham ∙ "Clean Up Your Mess — A Guide to Visual Design for Everyone" ∙ http://www.visualmess.com/
38. This is great if the visual relationships are
obvious and accurate, but if they're not, your
audience is going to get confused. They'll have to
examine your work carefully, going back and
forth between the different parts to make sure
they understand.
Daniel Higginbotham ∙ "Clean Up Your Mess — A Guide to Visual Design for Everyone" ∙ http://www.visualmess.com/
39. public int howNotToLayoutAMethodHeader(int firstArgument,
String secondArgument)
public int ensureArgumentsAreAlignedLikeThis(
int firstArgument,
String secondArgument)
public int orEnsureArgumentsAreGroupedLikeThis(
int firstArgument, String secondArgument)
public int butNotAlignedLikeThis(int firstArgument,
String secondArgument)
40. int doNotFormat = likeThis(someArgumentOrExpression,
anotherArgumentOrExpression);
int insteadFormat =
somethingLikeThis(
someArgumentOrExpression,
anotherArgumentOrExpression);
int orFormat = somethingLikeThis(
someArgumentOrExpression,
anotherArgumentOrExpression);
41. int asItIs = unstable(someArgumentOrExpression,
anotherArgumentOrExpression);
int butThisIs =
stable(
someArgumentOrExpression,
anotherArgumentOrExpression);
int andThisIs = stable(
someArgumentOrExpression,
anotherArgumentOrExpression);
51. Agglutination is a process in linguistic morphology
derivation in which complex words are formed by
stringing together morphemes, each with a single
grammatical or semantic meaning.
Languages that use agglutination widely are called
agglutinative languages.
http://en.wikipedia.org/wiki/Agglutination
56. People will be using the
words you choose in their
conversation for the next 20
years. You want to be sure
you do it right.
Unfortunately, many people
get all formal [...]. Just calling
it what it is isn't enough.
59. They have to tack on a
flowery, computer science-y,
impressive sounding, but
ultimately meaningless word,
like Object, Thing,
Component, Part, Manager,
Entity, or Item.
77. Don't ever invite a
vampire into your
house, you silly boy.
It renders you
powerless.
78. public class BankAccount
{
...
public decimal Balance
{
get ...
}
public void Deposit(decimal amount) ...
public void Withdraw(decimal amount) ...
...
}
85. public class Money implements ...
{
...
public int getUnits() ...
public int getHundredths() ...
public Currency getCurrency() ...
...
public void setUnits(int newUnits) ...
public void setHundredths(int newHundredths) ...
public void setCurrency(Currency newCurrency) ...
...
}
86. public final class Money implements ...
{
...
public int getUnits() ...
public int getHundredths() ...
public Currency getCurrency() ...
...
}
93. Everybody knows that TDD stands for Test Driven
Development. However, people too often concentrate
on the words "Test" and "Development" and don't
consider what the word "Driven" really implies.
For tests to drive development they must do more
than just test that code performs its required
functionality: they must clearly express that required
functionality to the reader.
That is, they must be clear specifications of the
required functionality. Tests that are not written with
their role as specifications in mind can be very
confusing to read.
Nat Pryce and Steve Freeman
"Are Your Tests Really Driving Your Development?"
96. public class Stack<T>
{
private
public Stack()
public void push(T newTop)
public void pop()
public int depth()
public T top()
}
97. public class StackTests
{
@Test
public void testConstructor()
@Test
public void testPush()
@Test
public void testPop()
@Test
public void testDepth()
@Test
public void testTop()
}
98. public class StackTests
{
@Test
public void constructor()
@Test
public void push()
@Test
public void pop()
@Test
public void depth()
@Test
public void top()
}
100. public class Stack_spec
{
public static class A_new_stack
{
@Test
public void is_empty()
}
public static class An_empty_stack
{
@Test()
public void throws_when_queried_for_its_top_item()
@Test()
public void throws_when_popped()
@Test
public void acquires_depth_by_retaining_a_pushed_item_as_its_top()
}
public static class A_non_empty_stack
{
@Test
public void becomes_deeper_by_retaining_a_pushed_item_as_its_top()
@Test
public void on_popping_reveals_tops_in_reverse_order_of_pushing()
}
}
101. public class
Stack_spec
{
public static class
A_new_stack
{
@Test
public void is_empty()
}
public static class
An_empty_stack
{
@Test()
public void throws_when_queried_for_its_top_item()
@Test()
public void throws_when_popped()
@Test
public void acquires_depth_by_retaining_a_pushed_item_as_its_top()
}
public static class
A_non_empty_stack
{
@Test
public void becomes_deeper_by_retaining_a_pushed_item_as_its_top()
@Test
public void on_popping_reveals_tops_in_reverse_order_of_pushing()
}
}
102. public class
Stack_spec
{
public static class
A_new_stack
{
@Test
public void is_empty()
}
public static class
An_empty_stack
{
@Test()
public void throws_when_queried_for_its_top_item()
@Test()
public void throws_when_popped()
@Test
public void acquires_depth_by_retaining_a_pushed_item_as_its_top()
}
public static class
A_non_empty_stack
{
@Test
public void becomes_deeper_by_retaining_a_pushed_item_as_its_top()
@Test
public void on_popping_reveals_tops_in_reverse_order_of_pushing()
}
}
103. function leftpad (str, len, ch) {
str = String(str);
var i = -1;
if (!ch && ch !== 0) ch = ' ';
len = len - str.length;
while (++i < len) {
str = ch + str;
}
return str;
}
104. function leftpad(content, length, pad) {
content = String(content)
pad = String(pad || pad === 0 ? pad : ' ')[0]
var left = Math.max(length - content.length, 0)
return pad.repeat(left) + content
}
106. function assert(condition) {
if(!condition)
throw { name: "AssertionError", message: "assertion failed" }
}
function testPasses(toTry) {
try {
toTry()
return true
} catch (failure) {
return false
}
}
function report(testName, passed) {
document.write(testName.fontcolor(passed ? "green" : "red") + "<br>")
}
function test(testCases) {
for (var testName in testCases)
if (testCases.hasOwnProperty(testName))
report(testName, testPasses(testCases[testName]))
}
107. test({
"Padding an empty string to a length of 0 results in an empty string":
() => assert(leftpad("", 0, "X") === ""),
"Padding a non-empty string to a shorter length results in the same string":
() => assert(leftpad("foobar", 3, "X") === "foobar"),
"Padding a non-empty string to a negative length results in the same string":
() => assert(leftpad("foobar", -3, "X") === "foobar"),
"Padding a non-empty string to its length results in the same string":
() => assert(leftpad("foobar", 6, "X") === "foobar"),
"Padding to a longer length with a single character fills to the left":
() => assert(leftpad("foobar", 8, "X") === "XXfoobar"),
"Padding to a longer length with surplus characters fills using only first":
() => assert(leftpad("foobar", 10, "XY") === "XXXXfoobar"),
"Padding to a longer length with an empty string fills with space":
() => assert(leftpad("foobar", 8, "") === " foobar"),
"Padding to a longer length with no specified fill fills with space":
() => assert(leftpad("foobar", 9) === " foobar"),
"Padding to a longer length with integer 0 fills with 0":
() => assert(leftpad("foobar", 7, 0) === "0foobar"),
"Padding to a longer length with single-digit integer fills with digit":
() => assert(leftpad("foobar", 10, 1) === "1111foobar"),
"Padding to a longer length with multiple-digit integer fills with first digit":
() => assert(leftpad("foobar", 10, 42) === "4444foobar"),
"Padding to a longer length with negative integer fills with -":
() => assert(leftpad("foobar", 8, -42) === "--foobar"),
"Padding a non-string uses string representation":
() => assert(leftpad(4.2, 5, 0) === "004.2")
})
108. Padding an empty string to a length of 0 results in an empty string
Padding a non-empty string to a shorter length results in the same string
Padding a non-empty string to a negative length results in the same string
Padding a non-empty string to its length results in the same string
Padding to a longer length with a single character fills to the left
Padding to a longer length with surplus characters fills using only first
Padding to a longer length with an empty string fills with space
Padding to a longer length with no specified fill fills with space
Padding to a longer length with integer 0 fills with 0
Padding to a longer length with single-digit integer fills with digit
Padding to a longer length with multiple-digit integer fills with first digit
Padding to a longer length with negative integer fills with -
Padding a non-string uses string representation
109. Padding an empty string to a length of 0 results in an empty string
Padding a non-empty string to a shorter length results in the same string
Padding a non-empty string to a negative length results in the same string
Padding a non-empty string to its length results in the same string
Padding to a longer length with a single character fills to the left
Padding to a longer length with surplus characters fills using only first
Padding to a longer length with an empty string fills with space
Padding to a longer length with no specified fill fills with space
Padding to a longer length with integer 0 fills with 0
Padding to a longer length with single-digit integer fills with digit
Padding to a longer length with multiple-digit integer fills with first digit
Padding to a longer length with negative integer fills with -
Padding a non-string uses string representation
110. A test case should
be just that: it
should correspond
to a single case.
111. As a
I want
So that
programmer
???
I can spend less time
determining the meaning
of code and more time
coding meaningfully
112. As a
I want
So that
programmer
code to communicate
directly and with intent
I can spend less time
determining the meaning
of code and more time
coding meaningfully