A talk describing how best practices for writing code have changed throughout the last 21 years.
What do we think of as good code, and how has our perception of good code changed form the early days of programming to the exciting times we live in now?
In this talk we do a bit of digging into the short history of programming, by looking at the available literature and various best practices promoted throughout the ages to improve your code.
5. The bookshelf
“A man may as well expect to
grow stronger by always eating
as wiser by always reading.”!
— Jeremy Collier
6. Writing Solid Code
❖ Steve Maguire!
❖ Microsoft Programming!
❖ 1993!
❖ “Microsoft’s Techniques for
Developing Bug-Free C
Programs”
7. The Pragmatic Programmer
❖ Andrew Hunt & David
Thomas!
❖ Addison Wesley!
❖ 2000!
❖ “examines the core process -
taking a requirement and
producing working, maintainable
code that delights its users”
8. Code Complete
❖ Steve McConnell!
❖ Microsoft Programming!
❖ 2004 (1st Edition 1993)!
❖ “A Practical Handbook of
Software Construction” - “Helps
you build the highest quality
code”
9. Clean Code
❖ Robert C. Martin (“Uncle Bob”)!
❖ Prentice Hall!
❖ 2009!
❖ “A handbook for Agile Software
Craftsmanship” — “How to write
good code and how to transform
bad code into good code”
10. 97 Things Every Programmer Should Know
❖ Various Artists, edited by
Kevlin Henney!
❖ O’Reilly!
❖ 2010!
❖ “Collective Wisdom from the
Experts” — “you’ll expand your
skills by … learning appropriate
best practices”
11. Growing Object-Oriented Software, Guided by Tests
❖ Steve Freeman & Nat Pryce!
❖ Addison Wesley!
❖ 2010!
❖ “Two TDD pioneers show how to
let tests guide your development
and ‘grow’ software that is
coherent, reliable, and
maintainable”
12. The Art of Readable Code
❖ Dustin Boswell & Trevor
Foucher!
❖ O’Reilly!
❖ 2011!
❖ “Simple and Practical Techniques
for Writing Better Code”
13. Guess the book!
“If we encounter a man of rare
intellect, we should ask him what
books he reads.”!
— Ralph Waldo Emerson
14. 2011
2009
! ! 1993
Use Hungarian notation for variables
❖ “Although names like pch look
funny and are hard to
pronounce, they are filled with
information.”!
❖ “Conveying information is far
more important in naming your
variables than being able to
stand up and read your code
aloud during a program
review.”
/* pointer to character
pointer */
char **ppch;
15. ! ! 1993
Use Hungarian notation for variables
❖ “Although names like pch look
funny and are hard to
pronounce, they are filled with
information.”!
❖ “Conveying information is far
more important in naming your
variables than being able to
stand up and read your code
aloud during a program
review.”
/* pointer to character
pointer */
char **ppch;
16. Don’t use Hungarian notation for variables
❖ “In modern languages we have
much richer type systems, and
the compilers remember and
enforce the types.”!
❖ “Nowadays HN and other
forms of type encoding are
simply impediments. They
make it harder to read the
code.”
/* pointer to character
pointer */
char **ppch;
2011
2009
! ! 1993
17. Don’t use Hungarian notation for variables
❖ “In modern languages we have
much richer type systems, and
the compilers remember and
enforce the types.”!
❖ “Nowadays HN and other
forms of type encoding are
simply impediments. They
make it harder to read the
code.”
/* pointer to character
pointer */
char **ppch;
2009
18. 2004
Don’t use Yoda Conditions
❖ “Putting constants and
expressions on the left-hand
side of comparisons works
only when one of the operands
is a constant or an expression.”!
❖ “If instead you use a compiler
switch, the compiler would
alert you to every possible
assignment bug.”
2011
! ! 1993
if (10 == x)
// if 10, x is!
19. Don’t use Yoda Conditions
❖ “Putting constants and
expressions on the left-hand
side of comparisons works
only when one of the operands
is a constant or an expression.”!
❖ “If instead you use a compiler
switch, the compiler would
alert you to every possible
assignment bug.”
if (10 == x)
// if 10, x is!
! ! 1993
20. 2010
Enforce singletons
❖ “If you want to define a class
that allows only one object to
be instantiated, enforce this by
hiding all the constructors of
the class and providing a static
routine to access the class’s
single instance.”
public class MaxId {
private MaxId() {}
public static MaxId
GetInstance() { /*..*/ }
}
2004
! ! 1993
21. Enforce singletons
❖ “If you want to define a class
that allows only one object to
be instantiated, enforce this by
hiding all the constructors of
the class and providing a static
routine to access the class’s
single instance.”
public class MaxId {
private MaxId() {}
public static MaxId
GetInstance() { /*..*/ }
}
2004
22. 2011
Prefer Write-Once Variables
❖ “The more places a variable is
manipulated, the harder it is to
reason about its current value”!
❖ “Variables that are a
‘permanent fixture’ are easier
to think about”!
❖ “Immutables tend to more
often be trouble-free”
2004
! ! 2000
23. 2011
Prefer Write-Once Variables
❖ “The more places a variable is
manipulated, the harder it is to
reason about its current value”!
❖ “Variables that are a
‘permanent fixture’ are easier
to think about”!
❖ “Immutables tend to more
often be trouble-free”
24. 2011
Design for Unit Tests
❖ “Most important, is it possible
to automatically and
thoroughly validate the design
using a unit test? If not, you
should consider using an
alternative design that can be
tested.”
2004
! ! 1993
25. Design for Unit Tests
❖ “Most important, is it possible
to automatically and
thoroughly validate the design
using a unit test? If not, you
should consider using an
alternative design that can be
tested.”
! ! 1993
27. Use Hungarian Notation for Variables
❖ Prefix indicates type or intended use!
❖ Widely used after use in Microsoft Windows C libraries!
❖ “Systems Hungarian” vs. “Apps Hungarian”
char ch; /* a plain old character */
bool f; /* flags that are always TRUE or FALSE */
char *pch; /* a character pointer */
char **ppch; /* pointer to a character pointer */
char *szName; /* a zero-terminated string */
28. Why?
❖ Makes wrong code ‘look wrong’ [Maguire93], [McConnell04]!
❖ Easy to decipher pointer expressions [McConnell04]!
❖ Semantic prefixes add information that compiler doesn’t
know about [McConnell04]!
❖ Standardized prefixes encourage consistent naming
[McConnell04]
29. Why not?
❖ Encoding adds burden of deciphering [Martin09]!
❖ Not necessary for types anymore [Martin09]!
❖ Functions and classes are shorter now [Martin09]!
❖ Inappropriate in object-oriented systems [Hunt00]!
❖ Code is read more than it’s written [Hunt00]
31. Specify interface or implementation in class name
❖ Denote in the class name when a class is an interface or
when it implements an interface!
❖ Typically using prefix ‘I’ for Interface and/or postfix
‘Impl’ for Implementation
class IBloober {
virtual void blob() = 0;
};
!
class BlooberImpl : public IBloober {
virtual void blob();
};
33. Why not?
❖ Users shouldn’t (have to) know they’re dealing with an
interface, better to encode the Impl [Martin09]!
❖ Names ending in Impl duplicate information [Freeman10]!
❖ Can indicate poorly named interface or design [Freeman10]
35. Align similar statements
❖ Can be used wherever similar statements are done on
multiple lines!
❖ Purely aesthetic enhancement
customerPurchases = customerPurchases + CustomerSales(customerID);
customerBill = customerBill + customerPurchases;
totalCustomerBill = customerBill + PreviousBalance(customerID) +
LateCharge(customerID);
customerRating = Rating(customerID, totalCustomerBill);
36. Why?
❖ Alignment scheme shows statements belong together
[McConnell93]!
❖ Neater listing and quicker scanning [McConnell93]!
❖ Column edges provide “visual handrails” [Boswell11]!
❖ Doesn’t take much work [Boswell11]
37. Why not?
❖ A headache to maintain as names change and lines are
moved amongst different indentations [McConnell04]!
❖ Emphasizes wrong things [Martin09]!
❖ Keep lists short [Martin09]!
❖ Eliminated by automatic reformatting tools [Martin09]
39. Keep functions short
❖ Functions should be as small as possible
std::string renderPageWithSetupsAndTeardowns(
PageData pageData, bool isSuite) {
if (isTestPage(pageData))
includeSetupAndTeardownPages(pageData, isSuite);
return pageData.getHtml();
}
40. Why?
❖ Easier to read and understand [Martin09]!
❖ Documentary value (descriptive name) [Martin09]!
❖ Easier to improve function when the code is by itself
[Boswell11]
41. Why not?
❖ Routines of longer length are no more error prone than
shorter routines, shorter may have more errors [McConnell93],
[McConnell04]!
❖ Routines of longer length are cheaper to develop
[McConnell93], [McConnell04]!
❖ Tiny functions can hurt readability [Boswell11]
44. Don’t Repeat Yourself (DRY)
❖ Every piece of code must have a single, unambiguous,
authoritative representation within a system [Hunt00]
45. Why?
❖ Change in one will make two implementations diverge
[Hunt00]!
❖ Similar code in two routines implies an error in
decomposition [McConnell93]!
❖ Duplication is a missed opportunity for abstraction
[Martin09]!
❖ Duplication can indicate bad design [Hunt00]!
❖ Copy/Paste programming is bad, remember Y2K [Hunt00]
47. Early Return
❖ Use guard clauses to return early for exceptional or
error conditions!
❖ Return early from e.g. linear search when a result is
found
public boolean Contains(String str, String substr) {
if (str == null || substr == null) return false;
if (substr.equals("")) return true;
...
}
48. Why?
❖ Implementing without guard clauses unnatural [Boswell11]!
❖ Avoids deep nesting [McConnell04], [Boswell11]!
❖ Single exit point less important with shorter functions
[Martin09]!
❖ Single exit point less important with modern languages
[Boswell11]
49. Why not?
❖ Breaks Structured Programming single-entry, single exit
‘law’ [Martin09]!
❖ Harder to understand a routine when unaware of all
return points [McConnell93]
51. Prefer Exceptions to Returning Error Codes
❖ Use exceptions to clarify the control flow
try {
socket.read(name);
process(name);
socket.read(address);
processAddress(address);
socket.read(telNo)
// etc, etc...
} catch (IOException e) {
Logger.log("Error reading individual: " +
e.getMessage());
}
52. Why?
❖ Clarifies normal flow of control [Hunt00]!
❖ Avoids violation of command query separation [Martin09]!
❖ Don’t force user to handle error immediately [Martin09]!
❖ Signal errors in a way that cannot be ignored [McConnell04]
53. Why not?
❖ High-level program flow obscured by bubbling up
[Boswell11]!
❖ Alternative error handling often more appropriate
[McConnell04]!
❖ Exceptions should only be used in exceptional
situations (that should never happen) [Hunt00]
55. Tell, Don’t Ask
❖ Objects make their decisions based only on the
information they hold internally or that which came
with the triggering message [Freeman10]
((EditSaveCustomizer) master.getModelisable()
.getDockablePanel()
.getCustomizer()
.getSaveItem().setEnabled(Boolean.FALSE.booleanValue());
!
// becomes...
master.allowSavingOfCustomisations();
59. Use Functional Programming Principles
❖ Use knowledge of functional programming in
imperative languages!
❖ Work with immutable data and pure functions where
possible
60. Why?
❖ Avoid side effects [Garson10]!
❖ Simpler to debug (source of change easy to find) [Garson10]!
❖ Avoid thread race conditions [Carmack12]!
❖ The more places a variable is manipulated, the harder it
is to reason about its value [Boswell11]
63. Program in Terms of the Problem Domain
❖ Model types and behavior in terms of the programming
problem rather than the computer science solution
if (portfolioIdsByTraderId.get(trader.getId())
.containsKey(portfolio.getId())) { ... }
!
// becomes ...
if (trader.canView(portfolio)) { ... }
64. Why?
❖ Increases code readability and understanding [North10]!
❖ Can evolve code when domain model evolves [North10]!
❖ Work at a higher level of abstraction to allow focusing
on solving domain problems [Hunt00]!
❖ Hides low-level details [McConnell93]!
❖ Separating solution and problem domain is part of the
job of a good programmer [Martin09]
65. Why not?
❖ The people who read your code are programmers: they
know CS terms [Martin09]
67. Prefer Message-Passing in Parallel Systems
❖ Use message passing instead of shared mutable
variables!
❖ Use copies of data where necessary!
❖ If the language doesn’t provide it, use libraries or
frameworks that do
68. Why?
❖ Shared mutable memory is at the root of problems
related to concurrency: race conditions, deadlock,
livelock [Winder10]!
❖ Proven way of handling concurrency [Winder10]!
❖ Avoiding synchronization makes up for overhead [Martin09]
70. Step Through your Code in a Debugger
❖ Actively step through all new or modified code to watch
it execute!
❖ As you step through code, focus on data flow!
❖ Step through every code path
71. Why?
❖ Allows you to get a ‘feeling’ for the code and gain
confidence [Maguire93]!
❖ You could create tests, but debugging is much faster
[Maguire93]
72. Why not?
❖ Problems can be found more quickly and more
accurately by thinking [McConnell04]!
❖ A bug should be reproducible with a single command
[Hunt00]
75. Why?
❖ Easier to test [Everyone]!
❖ Test-friendly code leads naturally to well-organized
code [Boswell11]!
❖ Decoupling leads to easier refactoring [Boswell11]!
❖ Classes with less state are simpler and easier to
understand [Boswell11]!
❖ Designing to test promotes reusability [Hunt00]
76. Why not?
❖ Could sacrifice readability for the sake of enabling tests
[Boswell11]!
❖ Testing by itself does not improve software quality
[McConnell93], [McConnell04]
78. Test-Driven Development
❖ Write test cases before writing code!
❖ Follow Red-Green-Refactor cycle!
❖ Do not write code without having test cases
79. Why?
❖ Forces you to think about requirements and design of
the code, finds problems earlier [McConnell04]!
❖ Tests will cover virtually all production code [Martin09]!
❖ Creates short feedback cycle in development [Freeman10]!
❖ Integrates refactoring in development [Freeman10]!
❖ Takes same amount of time as creating tests afterwards
[McConnell04]
80. Why not?
❖ Can create false sense of security (should not be only
form of testing) [McConnell04]!
❖ Just keeping testing in mind can help improve the code
[Boswell11]!
❖ Testing can get in the way of product development
[Boswell11]
82. Boy Scout Rule
❖ “Always leave the campground cleaner than you found
it”!
❖ When you check in a module, make a small
improvement, regardless of who the original author was
83. Why?
❖ The end of deterioration of software systems [Martin10]!
❖ Systems gradually get better [Martin10]!
❖ Promotes collective ownership [Martin10]!
❖ Don’t be afraid of the code [Lewis10]
84. Why not?
❖ What kind of motto is “If it ain’t broke, fix it anyway”?
[Maguire93]!
❖ Programmers don’t treat improved code as if it were
new code [Maguire93]!
❖ Your colleagues are not bozos, they might have had
their reasons [Maguire93]!
❖ Change in itself is not a virtue [McConnell04]
86. Conclusion
“The word is about,!
there's something evolving,!
whatever may come,!
the world keeps revolving!
!
They say the next big thing is here,!
that the revolution's near,!
but to me it seems quite clear!
that it's all just a little bit of history
repeating”!
!
—Alex Gifford by way of Shirley Bassey
Arjan van Leeuwen / @avl7771
87. Conclusion
❖ (Better) unit testing and test-driven development have
an impact on other practices!
❖ Concurrency finally having an impact, comeback of
functional language principles!
❖ Many practices that might seem recent were in fact
known for a long time
88. References
❖ [Boswell11] Dustin Boswell, Trevor Forcher, “The Art of Readable Code”. O’Reilly, 2011.!
❖ [Carmack12] John Carmack, “Functional Programming in C++”. http://www.altdevblogaday.com/2012/04/26/functional-
programming-in-c/, 2012.!
❖ [Freeman10] Steve Freeman, Nat Pryce, “Growing Object-Oriented Software”. Addison-Wesley, 2010.!
❖ [Garson10] Edward Garson, “Apply Functional Programming Principles”, from “97 Things Every Programmer Should Know”.
O’Reilly, 2010.!
❖ [Hunt00] Andrew Hunt, David Thomas, “The Pragmatic Programmer”. Addison-Wesley, 2000.!
❖ [Maguire93] Stephen A. Maguire, “Writing Solid Code”. Microsoft Press, 1993!
❖ [Martin09] Robert C. Martin, “Clean Code”. Prentice Hall, 2009.!
❖ [McConnell93] Steve McConnell, “Code Complete”. Microsoft Press, 1993!
❖ [McConnell04] Steve McConnell, “Code Complete 2”. Microsoft Press, 2004.!
❖ [North10] Dan North, “Code in the Language of the Domain”, from “97 Things Every Programmer Should Know”. O’Reilly, 2010.!
❖ [Winder10] Russel Winder, “Message Passing Leads to Better Scalability in Parallel Systems”, from “97 Things Every Programmer
Should Know”. O’Reilly, 2010.