Placeholders
All of these talking points are placeholders for a
conversation.
Many of the things that I talk about will make more
sense when we start to look at real code.
I’ve included sample code where I think it helps explain
the concepts, but the real code these lessons were
learned from was proprietary, so the examples might
seem a little over-simplistic.
The long and winding road
One of the biggest barriers to understandable code is
when it goes on too long.
As humans, we can only hold a certain amount of
context in our minds at any one time.
Methods that go on for tens of lines (or hundreds or
thousands) are too complex for us to understand
completely. The same is true of classes.
Reinvent the wheel?
It’s often easy to get into a problem solving mindset,
and that’s when we start writing code that’s probably
already been done
If we’re working on something not directly related to our
business domain, check for whether there’s already a
library.
For example, anything to do with the web, accessing the
disk or network, interacting with other processes.
Design Patterns
Design patterns are very useful to talk about code.
If we know the pattern name, we can discuss how this
code is doing what it’s doing
However
Design patterns do not tell us why we are doing something,
and so I don’t do design patterns. I make the code easier to
read and understand, and then afterwards say “Oh, I used a
Decorator there. Cool!”
System Metaphor
Often, when describing how a system works, we will use a metaphor.
We rarely capture this in the code.
System Metaphor
Often, when describing how a system works, we will use a metaphor.
We rarely capture this in the code.
What a shame :-(
System Metaphor
Often, when describing how a system works, we will use a metaphor.
We rarely capture this in the code.
What a shame :-(
A metaphor carries lots of information in a way that is
easy to share.
System Metaphor (cont.)
Metaphor
Useful information conveyed
Design Patterns
Language Idiom
Number of people who understand it
System Metaphor (cont.)
Metaphor Design Patterns
Useful information conveyed
Hard
Difficulty to Learn
Design Patterns
Language Idiom Metaphor
Language Idiom
Easy
Number of people who understand it Relevance to Domain
Guard clauses
if (weDontKnowWhichWireToCut()) { return new GetOutOfHereShesGonnaBlow(); }
if (someValue != null ) {
doSomething();
doSomethingElse();
doSomeMoreSomething();
return result;
}
return null; // This null is a long way from where we decided to send it
Guard clauses
if (weDontKnowWhichWireToCut()) { return new GetOutOfHereShesGonnaBlow(); }
if (someValue != null ) {
doSomething();
doSomethingElse();
doSomeMoreSomething();
return result;
}
return null; // This null is a long way from where we decided to send it
if (someValue == null ) { return null; } // Get out quickly
doSomething();
doSomethingElse();
doSomeMoreSomething();
return result;
Guard clauses (cont.)
Often, we hear “Only one exit point per method”
This makes sense in non-garbage-collected languages
because the exit point is a good place to tidy up
memory allocations.
It’s not really relevant in Java, and I’d rather know
quickly if there’s some short circuit decision I can make
if (!carStarted) { return callAA(); } // duh!
engageFirstGear();
if (carStarted) {
engageFirstGear();
… 100s of lines …
}
return callAA(); // Why am I calling the AA here?
Nested ifs
Cyclomatic complexity for nested ifs follows a geometric progression.
For a nest of 5 simple booleans, the number of possible paths is 32.
If we have 5 guard clauses, the number of paths is only 10
Look for “mountains” in the code
Cull Null
“I call it my billion-dollar mistake. It was the invention
of the null reference in 1965. […]
This has led to innumerable errors, vulnerabilities, and
system crashes, which have probably caused a billion
dollars of pain and damage in the last forty years.”
- Tony Hoare, QCon 2009
Cull Null
“I call it my billion-dollar mistake. It was the invention
of the null reference in 1965. […]
This has led to innumerable errors, vulnerabilities, and
system crashes, which have probably caused a billion
dollars of pain and damage in the last forty years.”
- Tony Hoare, QCon 2009
If we never return or expect null then we:
• no longer need null checks
• can trust that what we get is valid
• can trust that error handling is dealt with
elsewhere
Throw away Checked Exceptions
Typically checked exceptions are handled in one of two ways:
Throw away Checked Exceptions
Typically checked exceptions are handled in one of two ways:
public void someMethod() {
try {
File.open(“some file”);
} catch (IOException e) {
e.printStackTrace();
}
}
Throw away Checked Exceptions
Typically checked exceptions are handled in one of two ways:
public void someMethod() {
try {
File.open(“some file”); or
} catch (IOException e) {
e.printStackTrace();
}
}
Throw away Checked Exceptions
Typically checked exceptions are handled in one of two ways:
public void someMethod() { public void someMethod() throws IOException {
try {
File.open(“some file”); or }
File.open(“some file”);
} catch (IOException e) {
e.printStackTrace();
}
}
Throw away Checked Exceptions
Typically checked exceptions are handled in one of two ways:
public void someMethod() { public void someMethod() throws IOException {
try {
File.open(“some file”); or }
File.open(“some file”);
} catch (IOException e) {
e.printStackTrace();
}
}
Both of which essentially do nothing
Throw away Checked Exceptions
Typically checked exceptions are handled in one of two ways:
public void someMethod() { public void someMethod() throws IOException {
try {
File.open(“some file”); or }
File.open(“some file”);
} catch (IOException e) {
e.printStackTrace();
}
}
Both of which essentially do nothing
and worse... with the second option, details of the exception
bubble up far beyond where it makes sense to the caller
Throw away Checked Exceptions
Typically checked exceptions are handled in one of two ways:
public void someMethod() { public void someMethod() throws IOException {
try {
File.open(“some file”); or }
File.open(“some file”);
} catch (IOException e) {
e.printStackTrace();
}
}
Both of which essentially do nothing
and worse... with the second option, details of the exception
bubble up far beyond where it makes sense to the caller
If we want to do something, we can use and catch an unchecked
exception without all the pollution
Fail fast
If we know that it doesn’t make sense to continue, then
stop. NOW!
Don’t return a null or some other non-useful result when
we could let the caller know that something needs attention.
If we’re constructing an object (such as an email address)
and the email is not valid, we can throw an exception in the
constructor instead of having to check validity everywhere
the email is used.
In this way, everyone who uses an EmailAddress knows
that it’s a valid value.
Code metrics
Code metrics can give us good places to look for risky
code.
They help us discover areas of high complexity or areas
of high dependency.
Switch statements
Have you ever noticed that switch statements have the
word break all over the place, and frequently that’s
exactly what they do?
Switch statements
Have you ever noticed that switch statements have the
word break all over the place, and frequently that’s
exactly what they do?
switch statements are often an indication that we have a
Type that is trying to get out
Static methods
Static methods often appear in Utility classes.
This makes sense for objects that we don’t control
(such as any of the built-in libraries)
Static methods
Static methods often appear in Utility classes.
This makes sense for objects that we don’t control
(such as any of the built-in libraries)
Well, possibly...
Static methods
Static methods often appear in Utility classes.
This makes sense for objects that we don’t control
(such as any of the built-in libraries)
Well, possibly...
But it almost never makes sense for objects that we own.
Most static methods can be replaced with instance
methods that are easier to test and understand
Poor Man’s Dependency Injection
Add an overloaded version of the method or
constructor that takes the dependency, and new up the
dependency with a sensible default in the simpler case.
Poor Man’s Dependency Injection
Add an overloaded version of the method or
constructor that takes the dependency, and new up the
dependency with a sensible default in the simpler case.
public void someMethod() {
return someMethod(new Dependency());
}
public void someMethod(Dependency dependency) {
return dependency.doSomething();
}
I want to store £123.45
What data type should I use?
I want to store £123.45
What data type should I use?
float: The float data type is a single-precision 32-bit IEEE 754 floating point.
Use a float (instead of double) if you need to save memory in large arrays of floating
point numbers.
I want to store £123.45
What data type should I use?
float: The float data type is a single-precision 32-bit IEEE 754 floating point.
Use a float (instead of double) if you need to save memory in large arrays of floating
point numbers.
double: The double data type is a double-precision 64-bit IEEE 754 floating point.
I want to store £123.45
What data type should I use?
float: The float data type is a single-precision 32-bit IEEE 754 floating point.
Use a float (instead of double) if you need to save memory in large arrays of floating
point numbers.
double: The double data type is a double-precision 64-bit IEEE 754 floating point.
These data types should never be used for precise values, such as currency.
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
I want to store £123.45
What data type should I use?
float: The float data type is a single-precision 32-bit IEEE 754 floating point.
Use a float (instead of double) if you need to save memory in large arrays of floating
point numbers.
double: The double data type is a double-precision 64-bit IEEE 754 floating point.
These data types should never be used for precise values, such as currency.
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
Use the java.math.BigDecimal class instead
Avoid a void
void methods restrict our ability to extract composed methods
e.g., ServletFilter.doFilter for Authorisation
If we’re authorised, we want to continue to the resource
If we’re unauthenticated, then redirect us to the login page
If we’re unauthorised, redirect us to the Access Denied page
For the first case, we want to do a FilterChain.doFilter
For the others we don’t
Avoid a void (cont.)
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain) {
if (filterWorkflow() == Do.Filter) {
chain.doFilter(…);
}
}
public Do filterWorkflow() {
if (userIsAuthorised()) { return Do.Filter; }
if (userIsNotLoggedIn()) { return Do.Redirect(LoginPage); }
if (userIsNotAuthorised()) { return Do.Redirect(AccessDenied); }
}
Extending Exceptions
One of the things that I do in my code is to make an
obvious separation between types of exception.
I use Apology for something that the program should
reasonably have been able to do, but failed (like fetching
a User from a database)
I use Complaint for something that the program could
not possibly have achieved (like returning a single result
when the criteria specify multiple results)
Look outside of your area
One of the best books on programming that I’ve read is
called “Perl Medic”.
It covers most of what we’ve covered here and is
completely applicable to any language
(it’s just that the examples are in Perl)
Look outside of your area
One of the best books on programming that I’ve read is
called “Perl Medic”.
It covers most of what we’ve covered here and is
completely applicable to any language
(it’s just that the examples are in Perl)
Many .Netters who go to the Alt.Net events end up
migrating away from .Net once they see how easy it is
to do things in other languages.
Continuous Learning
I read blogs most days, across a wide variety of languages and topics.
A problem that someone has solved in another domain might be
transferrable to mine.
We’ve never learned everything, there’s always something new.
Go to a coding dojo, code retreat, or a language meetup (especially if
it’s for a language other than your own)
Hold “lunch and learns” or “after school clubs” in the office
(get the company to buy pizza)
Read books (I have lots of recommendations)
Question conventional wisdom