SlideShare a Scribd company logo
T
OGETHER, OPPOSITES CAN FORM A
memorable whole – love and hate,
yin and yang, elves and dwarves,
Fred Durst and Britney Spears. The
notion of such symmetry guides
expectations1, 2
. Sometimes the absence
of symmetry is jarring and
inconvenient; its presence simplifying
and predictable.
In interface design asymmetry can
keep you guessing and surprised rather
than informed and aware. The previous
two columns3, 4
have explored the
notion that the essence of an effective
interface lies in being concise,
consistent and conventional. Symmetry
is a form of consistency.
JUnit5
, the popular open-source unit
testing framework for Java, provides a
number of assertion methods to allow
programmers to test expected against
actual values. There is an assertTrue
method; there is also an assertFalse
method. There is an assertNull method;
there is also an assertNotNull method.
There is an assertSame method; there is
also an assertNotSame method. There is
an assertEquals method; there is no
assertNotEquals method. Oh. A hole in
the whole. Jarring and inconvenient.
Such an inconsistency is annoying
and tends to catch programmers out at
one time or another. Of course, it is
possible to work around it by
performing the relevant equality
comparison and passing the result to
assertFalse. However, not only does
this make a set of tests look
inconsistent, it can set up the
expectation that the normal way to
work with an interface is to workaround
its limitations – I certainly know APIs
for which this is true, but their existence
is grounds for caution, not a lead for
recommended practice. It is true that
one simple assertion is the absolute
minimum that you need6
, but the whole
point of a framework is that it captures
and expresses the common features of
your domain.
For a programmer to provide
assertNotEquals in JUnit would not be
complicated, but it would be tedious,
and this is perhaps one of the reasons it
does not yet exist. In truth, assertEquals
is not a method: it is a family of
overloaded methods, and quite a large
family at that. Because of limitations in
the existing Java language – contrary to
market hype, Java is not a fully or
consistently object-oriented language –
a variant of assertEquals is provided for
each built-in integral type (where == is
used for the comparison), for each
floating-point type (where comparison
is with respect to a delta rather than
strict equality) and for object types
(where the equals method is used). So,
although an intuitive interface to use, it
is a shopping list to implement and
document, involving no small amount
of copy-and-paste duplication.
To provide assertNotEquals would
involve providing the same number of
overloads again, along with the
associated implementation,
documentation and duplication. One
could make a case that this would bloat
the interface and make life for the
implementer more tedious. It is
certainly not an exciting task, but the
question is on which side of the
interface boundary should the slog and
repetition occur? Is it the
implementer’s responsibility or the
interface user’s problem? Put like that,
it seems clear that the convenience of
an interface should favour its user over
its implementer – write once, right for
many.
What about the question of bloat?
One of the guidelines for effective
interface design is that an interface
should be concise. However, concise is
not necessarily the same concept as
short: to be concise means to be both
brief and comprehensive. The measure
of an interface is not necessarily in the
number of methods it defines, but in
the number of ways it can be used. So,
although there are many assertEquals
overloads, there is only really one
assertEquals concept and only a couple
of ways of calling it, so the usage is
simple even if the actual Java method
listing is long.
Taken from this perspective it is clear
that the omission of assertNotEquals is
more of a pain than its potential
inclusion. Taken over time, it takes
longer to discover and explain its
absence than to include and use it. Note
that little or no explanation is required
for such opposites: if you know what
assertTrue does, then you know what
assertFalse does; if you are told what
assertSame does, you don’t need to be
told what assertNotSame does.
It is interesting to note that as JUnit
has evolved, its assertion interface has
become more symmetric. JUnit version
3.8 introduced assertFalse to pair with
assertTrue, an obvious completion.
assertTrue was introduced in version
3.7 to replace the assert method, which
clashed with the keyword of the same
name introduced in Java 1.4. However,
even before Java 1.4 forced the issue in
favour of a naming convention that
threw the question of symmetry into
sharp relief, an astute interface designer
might have pondered the absence of
assertNot as a partner for assert.
Of course, not every assertion has an
implied symmetry: JUnit’s
unconditional assertion, fail, has no
obvious complement. The absence of
failure defines success – likewise, “if we
do not succeed, then we run the risk of
failure”, to quote Dan Quayle, the
former US vice president, insightful
logician and orthographer
extraordinaire. Providing, or indeed
Symmetry has something to offer the world of
software. Kevlin Henney stands some interfaces in
front of the mirror to see what’s missing
OPPOSITES
ATTRACT
PROGRAMMERS’WORKSHOP KEVLIN HENNEY
48 APPLICATION DEVELOPMENT ADVISOR
Facts at a glance
• A symmetric pair of methods represent
some opposite aspect.
• The completeness of an interface can
sometimes be considered in terms of its
symmetry.
• Symmetry, or its absence, can affect
ease of use.
• But not everything is symmetric – that
would be forced and boring.
requiring, a succeed method would run
the risk of being both odd and
awkward.
Looking back at the Java
RecentlyUsedList interface described in
the previous two columns3, 4
, the most
obvious asymmetry is the absence of an
isFull query:
interface RecentlyUsedList
{
boolean isEmpty();
int size();
int capacity();
void clear();
void push(String newHead);
String elementAt(int index);
...
}
Just as list.isEmpty() more
accurately captures the essence of
list.size() == 0, list.isFull() would
better express the intent of list.size()
== list.capacity().
The ordering discipline encapsulated
by a recently used list ensures that the
most recently pushed is at the head and
the least recently pushed value is last.
The use of the push terminology
suggests perhaps a pop method could be
useful, losing the least recent entry.
Whether or not one chooses to
include these additional features, for
convenience or capability, symmetry
has certainly helped highlight them as
considerations:
interface RecentlyUsedList
{
boolean isEmpty();
boolean isFull();
int size();
int capacity();
void clear();
void push(String newHead);
String pop();
String elementAt(int index);
...
}
The symmetry between push and pop
is emphasised in their respective input
and output. However, symmetry in
code tends to be local, informal,
evocative and sketched; it is rarely a
global, formal, binding, mirror-perfect
relationship. For example, there is no
precondition on push, but pop cannot be
called on an empty list; a successful pop
always changes the visible state of the
list, whereas a push of the most recently
used item will leave the list unchanged.
Reasonable asymmetry
Of course, it is easy to become overly
enchanted by symmetry. For example,
having a habit or working to a
guideline to provide a setter with every
getter. Not only is this not a good idea,
it is actually quite a bad one7
.
Restricting object mutability either to
full immutability – whether by copy, by
class or by const8
– or to a few well-
defined and well-motivated state-
modifying methods is a more reasoned
and less error-prone path to take.
It is possible to query an entry in the
recently used list by index, but not to
set one by index. This is quite
reasonable: setting a value directly
would defeat the ordering discipline
that is the whole point of a recently
used list. It also leads to some
interesting questions concerning one of
the other invariants that govern the
data structure: entries are unique.
What would happen to the data
structure if an entry were set, by index,
to the value of an existing entry? There
are many possible interpretations and
responses, but few are worth pursuing.
Such behaviour is outside the scope of
a recently used list. The perceived
requirement demands either a revisit
or another solution. Scope creep often
arises because such questions are
answered in code rather than unasked.
A more reasonable symmetry
Conversely, a reasonable guideline is
that if you have a setter, there should
probably be a corresponding getter. To
be more precise, if an object has an
attribute, either conceptual or physical,
that can be modified by a method,
there should be some way of querying
that attribute. Failure to do so leads to
write-only attributes, which can be
frustrating to use and awkward – or
impossible – to test.
For (counter)example, Java’s
ArrayList class has an implied attribute
that describes its current capacity,
which is how many elements it can
hold without automatically resizing, as
opposed to its current size, which is the
number of elements it currently holds.
The capacity defaults to 10 on creation,
unless it is specified directly as a
constructor argument, and can be
specified explicitly using the
ensureCapacity method or trimmed to
the current required size using
trimToSize.
The documentation talks about the
capacity and how to change it, and the
concept is visible in the interface, but
there is no way to find out what it is.
This means that the capacity is
modifiable but unobservable, so the
capacity-related operations are
untestable: how would one write an
assertion to confirm that the default
constructed capacity was in fact 10?
This may at first seem academic:
testing the correctness of ArrayList is
surely Sun’s problem, so there is no
need to worry about the issue.
However, it is the design principle at
stake, not the specific example: there
ought to be a test somewhere – within
or without Sun – so what would it be?
It is interesting to note that
ArrayList’s less sophisticated, less well
reasoned and less focused predecessor,
Vector, offers the capacity query in
question.
Write-only attributes can be quite
subtle, and it is easy to miss them,
especially if you are the implementer.
Proximity to the implementation can
make it hard to share the interface
user’s perspective. A critical eye –
yours or someone else’s – or a test-
driven approach6, 9
can help to tune
into this line of symmetry. s
References
1. Kevlin Henney, “Five Possible
Things Before Breakfast”,
artima.com, June 2003,
www.artima.com/weblogs/
viewpost.jsp?thread=5432
2. Kevlin Henney, “Factory and
Disposal Methods”, VikingPLoP
2003, September 2003, available
from www.curbralan.com
3. Kevlin Henney, “Form Follows
Function”, App Dev Advisor,
March 2004.
4. Kevlin Henney, “Conventional and
Reasonable”, App Dev Advisor,
May 2004.
5. JUnit, available from http://junit.org
6. Kevlin Henney, “Put to the Test”,
App Dev Advisor, November 2002.
7. Kevlin Henney, “The Good, the Bad,
and the Koyaanisqatsi”, VikingPLoP
2003, September 2003, available
from www.curbralan.com
8. Kevlin Henney, “Objects of Value”,
App Dev Advisor, November 2003.
9. Kent Beck, Test-Driven
Development by Example, Addison-
Wesley, 2003.
KEVLIN HENNEY PROGRAMMERS’WORKSHOP
JULY-AUGUST 2004 49

More Related Content

What's hot

Exceptional Naming
Exceptional NamingExceptional Naming
Exceptional Naming
Kevlin Henney
 
09 grasp
09 grasp09 grasp
Design poo my_jug_en_ppt
Design poo my_jug_en_pptDesign poo my_jug_en_ppt
Design poo my_jug_en_ppt
agnes_crepet
 
What's in a Name?
What's in a Name?What's in a Name?
What's in a Name?
Kevlin Henney
 
GRASP Principles
GRASP PrinciplesGRASP Principles
GRASP Principles
Raheel Arif
 
Grasp principles
Grasp principlesGrasp principles
Grasp principles
Yuriy Shapovalov
 
Grasp
GraspGrasp
Final grasp ASE
Final grasp ASEFinal grasp ASE
Final grasp ASE
babak danyal
 
How I Learned To Apply Design Patterns
How I Learned To Apply Design PatternsHow I Learned To Apply Design Patterns
How I Learned To Apply Design Patterns
Andy Maleh
 
SAD10 - Refactoring
SAD10 - RefactoringSAD10 - Refactoring
SAD10 - Refactoring
Michael Heron
 
ScalaItaly 2015 - Your Microservice as a Function
ScalaItaly 2015 - Your Microservice as a FunctionScalaItaly 2015 - Your Microservice as a Function
ScalaItaly 2015 - Your Microservice as a Function
Phil Calçado
 
Systematic error management - we ported rudder to zio
Systematic error management - we ported rudder to zioSystematic error management - we ported rudder to zio
Systematic error management - we ported rudder to zio
fanf42
 
Code Smells
Code SmellsCode Smells
How To Navigate And Extend The Flex Infrastructure
How To Navigate And Extend The Flex InfrastructureHow To Navigate And Extend The Flex Infrastructure
How To Navigate And Extend The Flex Infrastructuremichael.labriola
 
L12 GRASP
L12 GRASPL12 GRASP
Refactoring: Improve the design of existing code
Refactoring: Improve the design of existing codeRefactoring: Improve the design of existing code
Refactoring: Improve the design of existing code
Valerio Maggio
 
Lecture 18
Lecture 18Lecture 18
Lecture 18
talha ijaz
 
Assessing Product Line Derivation Operators Applied to Java Source Code: An E...
Assessing Product Line Derivation Operators Applied to Java Source Code: An E...Assessing Product Line Derivation Operators Applied to Java Source Code: An E...
Assessing Product Line Derivation Operators Applied to Java Source Code: An E...
University of Rennes, INSA Rennes, Inria/IRISA, CNRS
 
Refactoring for Software Design Smells - Tech Talk
Refactoring for Software Design Smells - Tech TalkRefactoring for Software Design Smells - Tech Talk
Refactoring for Software Design Smells - Tech Talk
Ganesh Samarthyam
 

What's hot (20)

Exceptional Naming
Exceptional NamingExceptional Naming
Exceptional Naming
 
09 grasp
09 grasp09 grasp
09 grasp
 
Design poo my_jug_en_ppt
Design poo my_jug_en_pptDesign poo my_jug_en_ppt
Design poo my_jug_en_ppt
 
What's in a Name?
What's in a Name?What's in a Name?
What's in a Name?
 
GRASP Principles
GRASP PrinciplesGRASP Principles
GRASP Principles
 
Grasp principles
Grasp principlesGrasp principles
Grasp principles
 
Grasp
GraspGrasp
Grasp
 
Final grasp ASE
Final grasp ASEFinal grasp ASE
Final grasp ASE
 
How I Learned To Apply Design Patterns
How I Learned To Apply Design PatternsHow I Learned To Apply Design Patterns
How I Learned To Apply Design Patterns
 
SAD10 - Refactoring
SAD10 - RefactoringSAD10 - Refactoring
SAD10 - Refactoring
 
ScalaItaly 2015 - Your Microservice as a Function
ScalaItaly 2015 - Your Microservice as a FunctionScalaItaly 2015 - Your Microservice as a Function
ScalaItaly 2015 - Your Microservice as a Function
 
Presentation
PresentationPresentation
Presentation
 
Systematic error management - we ported rudder to zio
Systematic error management - we ported rudder to zioSystematic error management - we ported rudder to zio
Systematic error management - we ported rudder to zio
 
Code Smells
Code SmellsCode Smells
Code Smells
 
How To Navigate And Extend The Flex Infrastructure
How To Navigate And Extend The Flex InfrastructureHow To Navigate And Extend The Flex Infrastructure
How To Navigate And Extend The Flex Infrastructure
 
L12 GRASP
L12 GRASPL12 GRASP
L12 GRASP
 
Refactoring: Improve the design of existing code
Refactoring: Improve the design of existing codeRefactoring: Improve the design of existing code
Refactoring: Improve the design of existing code
 
Lecture 18
Lecture 18Lecture 18
Lecture 18
 
Assessing Product Line Derivation Operators Applied to Java Source Code: An E...
Assessing Product Line Derivation Operators Applied to Java Source Code: An E...Assessing Product Line Derivation Operators Applied to Java Source Code: An E...
Assessing Product Line Derivation Operators Applied to Java Source Code: An E...
 
Refactoring for Software Design Smells - Tech Talk
Refactoring for Software Design Smells - Tech TalkRefactoring for Software Design Smells - Tech Talk
Refactoring for Software Design Smells - Tech Talk
 

Viewers also liked

Downlight for commercial lighting application
Downlight for commercial lighting application Downlight for commercial lighting application
Downlight for commercial lighting application
Ladislav Varga
 
A Salesforce Admin's Compass to Dreamforce
A Salesforce Admin's Compass to DreamforceA Salesforce Admin's Compass to Dreamforce
A Salesforce Admin's Compass to Dreamforce
Salesforce Admins
 
Unleashing People Potential
Unleashing People PotentialUnleashing People Potential
Unleashing People PotentialAnand Desai
 
CATALOGO ESCLAVAS
CATALOGO ESCLAVASCATALOGO ESCLAVAS
CATALOGO ESCLAVASjoyas_plata
 
Grafico diario del dax perfomance index para el 08 08-2012
Grafico diario del dax perfomance index para el 08 08-2012Grafico diario del dax perfomance index para el 08 08-2012
Grafico diario del dax perfomance index para el 08 08-2012Experiencia Trading
 
Extreme Leadership - How To Unleash The Full Potential In People And Teams
Extreme Leadership - How To Unleash The Full Potential In People And TeamsExtreme Leadership - How To Unleash The Full Potential In People And Teams
Extreme Leadership - How To Unleash The Full Potential In People And Teams
Ferdinand von den Eichen
 
Reunião de Câmara 05/11/2013 - Ponto 10
Reunião de Câmara 05/11/2013 - Ponto 10Reunião de Câmara 05/11/2013 - Ponto 10
Reunião de Câmara 05/11/2013 - Ponto 10
Pedro Pires
 
Адаптация бурошнековых машин и инструмента к условиям эксплуатации
Адаптация бурошнековых машин и инструмента к условиям эксплуатацииАдаптация бурошнековых машин и инструмента к условиям эксплуатации
Адаптация бурошнековых машин и инструмента к условиям эксплуатацииkulibin
 
Plato
PlatoPlato
Plato
Hunki Kim
 
Social media nonprofitcenter0913
Social media nonprofitcenter0913Social media nonprofitcenter0913
Social media nonprofitcenter0913Jan Hirabayashi
 
Book secrets of success of IIIT model
Book secrets of success of IIIT modelBook secrets of success of IIIT model
Book secrets of success of IIIT model
Prof. Dr. Rajiv Dharaskar PhD (Comp)
 
Фотоотчёт о фестивале покров
Фотоотчёт о фестивале покровФотоотчёт о фестивале покров
Фотоотчёт о фестивале покров
Ирина Мамаева
 
Wearable Computing Devices - The Next Big Thing!
Wearable Computing Devices - The Next Big Thing!Wearable Computing Devices - The Next Big Thing!
Wearable Computing Devices - The Next Big Thing!
Aranca
 
Why people do not reach their potential 080113
Why people do not reach their potential 080113Why people do not reach their potential 080113
Why people do not reach their potential 080113
Lars Ray, CC, MCC
 
Understanding the bronchiectasis prognosis
Understanding the bronchiectasis prognosisUnderstanding the bronchiectasis prognosis
Understanding the bronchiectasis prognosis
Sugeng Hartono
 
BioConference Live Genetics 2013
BioConference Live Genetics 2013BioConference Live Genetics 2013
BioConference Live Genetics 2013LabRoots, Inc.
 
Shearwater net suite ecommerce solution
Shearwater net suite ecommerce solutionShearwater net suite ecommerce solution
Shearwater net suite ecommerce solution
baptisteshearwater
 
Ensayo formacion de alumnos para el futuro
Ensayo  formacion de alumnos para el futuroEnsayo  formacion de alumnos para el futuro
Ensayo formacion de alumnos para el futuro
petramalena
 
Home Buyers Guide
Home Buyers Guide Home Buyers Guide
Home Buyers Guide
Socially Savvy
 

Viewers also liked (20)

Downlight for commercial lighting application
Downlight for commercial lighting application Downlight for commercial lighting application
Downlight for commercial lighting application
 
A Salesforce Admin's Compass to Dreamforce
A Salesforce Admin's Compass to DreamforceA Salesforce Admin's Compass to Dreamforce
A Salesforce Admin's Compass to Dreamforce
 
Unleashing People Potential
Unleashing People PotentialUnleashing People Potential
Unleashing People Potential
 
CATALOGO ESCLAVAS
CATALOGO ESCLAVASCATALOGO ESCLAVAS
CATALOGO ESCLAVAS
 
Grafico diario del dax perfomance index para el 08 08-2012
Grafico diario del dax perfomance index para el 08 08-2012Grafico diario del dax perfomance index para el 08 08-2012
Grafico diario del dax perfomance index para el 08 08-2012
 
Extreme Leadership - How To Unleash The Full Potential In People And Teams
Extreme Leadership - How To Unleash The Full Potential In People And TeamsExtreme Leadership - How To Unleash The Full Potential In People And Teams
Extreme Leadership - How To Unleash The Full Potential In People And Teams
 
Reunião de Câmara 05/11/2013 - Ponto 10
Reunião de Câmara 05/11/2013 - Ponto 10Reunião de Câmara 05/11/2013 - Ponto 10
Reunião de Câmara 05/11/2013 - Ponto 10
 
Адаптация бурошнековых машин и инструмента к условиям эксплуатации
Адаптация бурошнековых машин и инструмента к условиям эксплуатацииАдаптация бурошнековых машин и инструмента к условиям эксплуатации
Адаптация бурошнековых машин и инструмента к условиям эксплуатации
 
Plato
PlatoPlato
Plato
 
Trabajo
TrabajoTrabajo
Trabajo
 
Social media nonprofitcenter0913
Social media nonprofitcenter0913Social media nonprofitcenter0913
Social media nonprofitcenter0913
 
Book secrets of success of IIIT model
Book secrets of success of IIIT modelBook secrets of success of IIIT model
Book secrets of success of IIIT model
 
Фотоотчёт о фестивале покров
Фотоотчёт о фестивале покровФотоотчёт о фестивале покров
Фотоотчёт о фестивале покров
 
Wearable Computing Devices - The Next Big Thing!
Wearable Computing Devices - The Next Big Thing!Wearable Computing Devices - The Next Big Thing!
Wearable Computing Devices - The Next Big Thing!
 
Why people do not reach their potential 080113
Why people do not reach their potential 080113Why people do not reach their potential 080113
Why people do not reach their potential 080113
 
Understanding the bronchiectasis prognosis
Understanding the bronchiectasis prognosisUnderstanding the bronchiectasis prognosis
Understanding the bronchiectasis prognosis
 
BioConference Live Genetics 2013
BioConference Live Genetics 2013BioConference Live Genetics 2013
BioConference Live Genetics 2013
 
Shearwater net suite ecommerce solution
Shearwater net suite ecommerce solutionShearwater net suite ecommerce solution
Shearwater net suite ecommerce solution
 
Ensayo formacion de alumnos para el futuro
Ensayo  formacion de alumnos para el futuroEnsayo  formacion de alumnos para el futuro
Ensayo formacion de alumnos para el futuro
 
Home Buyers Guide
Home Buyers Guide Home Buyers Guide
Home Buyers Guide
 

Similar to Opposites Attract

SELFLESS INHERITANCE
SELFLESS INHERITANCESELFLESS INHERITANCE
SELFLESS INHERITANCE
ijpla
 
Something for Nothing
Something for NothingSomething for Nothing
Something for Nothing
Kevlin Henney
 
A Tale of Three Patterns
A Tale of Three PatternsA Tale of Three Patterns
A Tale of Three Patterns
Kevlin Henney
 
Creating Stable Assignments
Creating Stable AssignmentsCreating Stable Assignments
Creating Stable Assignments
Kevlin Henney
 
scala-intro
scala-introscala-intro
scala-intro
Manav Prasad
 
Java mcq
Java mcqJava mcq
Java mcq
avinash9821
 
Six of the Best
Six of the BestSix of the Best
Six of the Best
Kevlin Henney
 
AEM Clean Code - Miklos Csere
AEM Clean Code - Miklos Csere AEM Clean Code - Miklos Csere
AEM Clean Code - Miklos Csere Miklos Csere
 
A Tale of Two Patterns
A Tale of Two PatternsA Tale of Two Patterns
A Tale of Two Patterns
Kevlin Henney
 
Advance oops concepts
Advance oops conceptsAdvance oops concepts
Advance oops concepts
Sangharsh agarwal
 
Substitutability
SubstitutabilitySubstitutability
Substitutability
Kevlin Henney
 
Java Faqs useful for freshers and experienced
Java Faqs useful for freshers and experiencedJava Faqs useful for freshers and experienced
Java Faqs useful for freshers and experiencedyearninginjava
 
Another Tale of Two Patterns
Another Tale of Two PatternsAnother Tale of Two Patterns
Another Tale of Two Patterns
Kevlin Henney
 
Top 371 java fa qs useful for freshers and experienced
Top 371 java fa qs useful for freshers and experiencedTop 371 java fa qs useful for freshers and experienced
Top 371 java fa qs useful for freshers and experiencedGaurav Maheshwari
 
‘go-to’ general-purpose sequential collections - from Java To Scala
‘go-to’ general-purpose sequential collections -from Java To Scala‘go-to’ general-purpose sequential collections -from Java To Scala
‘go-to’ general-purpose sequential collections - from Java To Scala
Philip Schwarz
 
Grooming with Groovy
Grooming with GroovyGrooming with Groovy
Grooming with Groovy
Dhaval Dalal
 
50+ java interview questions
50+ java interview questions50+ java interview questions
50+ java interview questions
SynergisticMedia
 
Using the Machine to predict Testability
Using the Machine to predict TestabilityUsing the Machine to predict Testability
Using the Machine to predict Testability
Miguel Lopez
 
Figure 1
Figure 1Figure 1
Figure 1butest
 

Similar to Opposites Attract (20)

SELFLESS INHERITANCE
SELFLESS INHERITANCESELFLESS INHERITANCE
SELFLESS INHERITANCE
 
Something for Nothing
Something for NothingSomething for Nothing
Something for Nothing
 
A Tale of Three Patterns
A Tale of Three PatternsA Tale of Three Patterns
A Tale of Three Patterns
 
Creating Stable Assignments
Creating Stable AssignmentsCreating Stable Assignments
Creating Stable Assignments
 
scala-intro
scala-introscala-intro
scala-intro
 
Java mcq
Java mcqJava mcq
Java mcq
 
Six of the Best
Six of the BestSix of the Best
Six of the Best
 
AEM Clean Code - Miklos Csere
AEM Clean Code - Miklos Csere AEM Clean Code - Miklos Csere
AEM Clean Code - Miklos Csere
 
A Tale of Two Patterns
A Tale of Two PatternsA Tale of Two Patterns
A Tale of Two Patterns
 
Advance oops concepts
Advance oops conceptsAdvance oops concepts
Advance oops concepts
 
Substitutability
SubstitutabilitySubstitutability
Substitutability
 
Java Faqs useful for freshers and experienced
Java Faqs useful for freshers and experiencedJava Faqs useful for freshers and experienced
Java Faqs useful for freshers and experienced
 
Another Tale of Two Patterns
Another Tale of Two PatternsAnother Tale of Two Patterns
Another Tale of Two Patterns
 
Top 371 java fa qs useful for freshers and experienced
Top 371 java fa qs useful for freshers and experiencedTop 371 java fa qs useful for freshers and experienced
Top 371 java fa qs useful for freshers and experienced
 
‘go-to’ general-purpose sequential collections - from Java To Scala
‘go-to’ general-purpose sequential collections -from Java To Scala‘go-to’ general-purpose sequential collections -from Java To Scala
‘go-to’ general-purpose sequential collections - from Java To Scala
 
Grooming with Groovy
Grooming with GroovyGrooming with Groovy
Grooming with Groovy
 
Suga java training_with_footer
Suga java training_with_footerSuga java training_with_footer
Suga java training_with_footer
 
50+ java interview questions
50+ java interview questions50+ java interview questions
50+ java interview questions
 
Using the Machine to predict Testability
Using the Machine to predict TestabilityUsing the Machine to predict Testability
Using the Machine to predict Testability
 
Figure 1
Figure 1Figure 1
Figure 1
 

More from Kevlin Henney

Program with GUTs
Program with GUTsProgram with GUTs
Program with GUTs
Kevlin Henney
 
The Case for Technical Excellence
The Case for Technical ExcellenceThe Case for Technical Excellence
The Case for Technical Excellence
Kevlin Henney
 
Empirical Development
Empirical DevelopmentEmpirical Development
Empirical Development
Kevlin Henney
 
Lambda? You Keep Using that Letter
Lambda? You Keep Using that LetterLambda? You Keep Using that Letter
Lambda? You Keep Using that Letter
Kevlin Henney
 
Lambda? You Keep Using that Letter
Lambda? You Keep Using that LetterLambda? You Keep Using that Letter
Lambda? You Keep Using that Letter
Kevlin Henney
 
Solid Deconstruction
Solid DeconstructionSolid Deconstruction
Solid Deconstruction
Kevlin Henney
 
Get Kata
Get KataGet Kata
Get Kata
Kevlin Henney
 
Procedural Programming: It’s Back? It Never Went Away
Procedural Programming: It’s Back? It Never Went AwayProcedural Programming: It’s Back? It Never Went Away
Procedural Programming: It’s Back? It Never Went Away
Kevlin Henney
 
Structure and Interpretation of Test Cases
Structure and Interpretation of Test CasesStructure and Interpretation of Test Cases
Structure and Interpretation of Test Cases
Kevlin Henney
 
Agility ≠ Speed
Agility ≠ SpeedAgility ≠ Speed
Agility ≠ Speed
Kevlin Henney
 
Refactoring to Immutability
Refactoring to ImmutabilityRefactoring to Immutability
Refactoring to Immutability
Kevlin Henney
 
Old Is the New New
Old Is the New NewOld Is the New New
Old Is the New New
Kevlin Henney
 
Turning Development Outside-In
Turning Development Outside-InTurning Development Outside-In
Turning Development Outside-In
Kevlin Henney
 
Giving Code a Good Name
Giving Code a Good NameGiving Code a Good Name
Giving Code a Good Name
Kevlin Henney
 
Clean Coders Hate What Happens To Your Code When You Use These Enterprise Pro...
Clean Coders Hate What Happens To Your Code When You Use These Enterprise Pro...Clean Coders Hate What Happens To Your Code When You Use These Enterprise Pro...
Clean Coders Hate What Happens To Your Code When You Use These Enterprise Pro...
Kevlin Henney
 
Thinking Outside the Synchronisation Quadrant
Thinking Outside the Synchronisation QuadrantThinking Outside the Synchronisation Quadrant
Thinking Outside the Synchronisation Quadrant
Kevlin Henney
 
Code as Risk
Code as RiskCode as Risk
Code as Risk
Kevlin Henney
 
Software Is Details
Software Is DetailsSoftware Is Details
Software Is Details
Kevlin Henney
 
Game of Sprints
Game of SprintsGame of Sprints
Game of Sprints
Kevlin Henney
 
Good Code
Good CodeGood Code
Good Code
Kevlin Henney
 

More from Kevlin Henney (20)

Program with GUTs
Program with GUTsProgram with GUTs
Program with GUTs
 
The Case for Technical Excellence
The Case for Technical ExcellenceThe Case for Technical Excellence
The Case for Technical Excellence
 
Empirical Development
Empirical DevelopmentEmpirical Development
Empirical Development
 
Lambda? You Keep Using that Letter
Lambda? You Keep Using that LetterLambda? You Keep Using that Letter
Lambda? You Keep Using that Letter
 
Lambda? You Keep Using that Letter
Lambda? You Keep Using that LetterLambda? You Keep Using that Letter
Lambda? You Keep Using that Letter
 
Solid Deconstruction
Solid DeconstructionSolid Deconstruction
Solid Deconstruction
 
Get Kata
Get KataGet Kata
Get Kata
 
Procedural Programming: It’s Back? It Never Went Away
Procedural Programming: It’s Back? It Never Went AwayProcedural Programming: It’s Back? It Never Went Away
Procedural Programming: It’s Back? It Never Went Away
 
Structure and Interpretation of Test Cases
Structure and Interpretation of Test CasesStructure and Interpretation of Test Cases
Structure and Interpretation of Test Cases
 
Agility ≠ Speed
Agility ≠ SpeedAgility ≠ Speed
Agility ≠ Speed
 
Refactoring to Immutability
Refactoring to ImmutabilityRefactoring to Immutability
Refactoring to Immutability
 
Old Is the New New
Old Is the New NewOld Is the New New
Old Is the New New
 
Turning Development Outside-In
Turning Development Outside-InTurning Development Outside-In
Turning Development Outside-In
 
Giving Code a Good Name
Giving Code a Good NameGiving Code a Good Name
Giving Code a Good Name
 
Clean Coders Hate What Happens To Your Code When You Use These Enterprise Pro...
Clean Coders Hate What Happens To Your Code When You Use These Enterprise Pro...Clean Coders Hate What Happens To Your Code When You Use These Enterprise Pro...
Clean Coders Hate What Happens To Your Code When You Use These Enterprise Pro...
 
Thinking Outside the Synchronisation Quadrant
Thinking Outside the Synchronisation QuadrantThinking Outside the Synchronisation Quadrant
Thinking Outside the Synchronisation Quadrant
 
Code as Risk
Code as RiskCode as Risk
Code as Risk
 
Software Is Details
Software Is DetailsSoftware Is Details
Software Is Details
 
Game of Sprints
Game of SprintsGame of Sprints
Game of Sprints
 
Good Code
Good CodeGood Code
Good Code
 

Recently uploaded

LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOMLORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
lorraineandreiamcidl
 
A Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of PassageA Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of Passage
Philip Schwarz
 
Large Language Models and the End of Programming
Large Language Models and the End of ProgrammingLarge Language Models and the End of Programming
Large Language Models and the End of Programming
Matt Welsh
 
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Globus
 
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI AppAI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
Google
 
Enterprise Resource Planning System in Telangana
Enterprise Resource Planning System in TelanganaEnterprise Resource Planning System in Telangana
Enterprise Resource Planning System in Telangana
NYGGS Automation Suite
 
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data AnalysisProviding Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Globus
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
Globus
 
AI Genie Review: World’s First Open AI WordPress Website Creator
AI Genie Review: World’s First Open AI WordPress Website CreatorAI Genie Review: World’s First Open AI WordPress Website Creator
AI Genie Review: World’s First Open AI WordPress Website Creator
Google
 
Pro Unity Game Development with C-sharp Book
Pro Unity Game Development with C-sharp BookPro Unity Game Development with C-sharp Book
Pro Unity Game Development with C-sharp Book
abdulrafaychaudhry
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
Safe Software
 
2024 eCommerceDays Toulouse - Sylius 2.0.pdf
2024 eCommerceDays Toulouse - Sylius 2.0.pdf2024 eCommerceDays Toulouse - Sylius 2.0.pdf
2024 eCommerceDays Toulouse - Sylius 2.0.pdf
Łukasz Chruściel
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024
Globus
 
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
Juraj Vysvader
 
openEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain SecurityopenEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain Security
Shane Coughlan
 
Mobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona InfotechMobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona Infotech
Drona Infotech
 
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
Aftab Hussain
 
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing SuiteAI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
Google
 
GraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph TechnologyGraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph Technology
Neo4j
 

Recently uploaded (20)

LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOMLORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
 
A Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of PassageA Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of Passage
 
Large Language Models and the End of Programming
Large Language Models and the End of ProgrammingLarge Language Models and the End of Programming
Large Language Models and the End of Programming
 
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
 
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI AppAI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
 
Enterprise Resource Planning System in Telangana
Enterprise Resource Planning System in TelanganaEnterprise Resource Planning System in Telangana
Enterprise Resource Planning System in Telangana
 
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data AnalysisProviding Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
 
AI Genie Review: World’s First Open AI WordPress Website Creator
AI Genie Review: World’s First Open AI WordPress Website CreatorAI Genie Review: World’s First Open AI WordPress Website Creator
AI Genie Review: World’s First Open AI WordPress Website Creator
 
Pro Unity Game Development with C-sharp Book
Pro Unity Game Development with C-sharp BookPro Unity Game Development with C-sharp Book
Pro Unity Game Development with C-sharp Book
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
 
2024 eCommerceDays Toulouse - Sylius 2.0.pdf
2024 eCommerceDays Toulouse - Sylius 2.0.pdf2024 eCommerceDays Toulouse - Sylius 2.0.pdf
2024 eCommerceDays Toulouse - Sylius 2.0.pdf
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024
 
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
 
openEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain SecurityopenEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain Security
 
Mobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona InfotechMobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona Infotech
 
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
 
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing SuiteAI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
 
GraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph TechnologyGraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph Technology
 

Opposites Attract

  • 1. T OGETHER, OPPOSITES CAN FORM A memorable whole – love and hate, yin and yang, elves and dwarves, Fred Durst and Britney Spears. The notion of such symmetry guides expectations1, 2 . Sometimes the absence of symmetry is jarring and inconvenient; its presence simplifying and predictable. In interface design asymmetry can keep you guessing and surprised rather than informed and aware. The previous two columns3, 4 have explored the notion that the essence of an effective interface lies in being concise, consistent and conventional. Symmetry is a form of consistency. JUnit5 , the popular open-source unit testing framework for Java, provides a number of assertion methods to allow programmers to test expected against actual values. There is an assertTrue method; there is also an assertFalse method. There is an assertNull method; there is also an assertNotNull method. There is an assertSame method; there is also an assertNotSame method. There is an assertEquals method; there is no assertNotEquals method. Oh. A hole in the whole. Jarring and inconvenient. Such an inconsistency is annoying and tends to catch programmers out at one time or another. Of course, it is possible to work around it by performing the relevant equality comparison and passing the result to assertFalse. However, not only does this make a set of tests look inconsistent, it can set up the expectation that the normal way to work with an interface is to workaround its limitations – I certainly know APIs for which this is true, but their existence is grounds for caution, not a lead for recommended practice. It is true that one simple assertion is the absolute minimum that you need6 , but the whole point of a framework is that it captures and expresses the common features of your domain. For a programmer to provide assertNotEquals in JUnit would not be complicated, but it would be tedious, and this is perhaps one of the reasons it does not yet exist. In truth, assertEquals is not a method: it is a family of overloaded methods, and quite a large family at that. Because of limitations in the existing Java language – contrary to market hype, Java is not a fully or consistently object-oriented language – a variant of assertEquals is provided for each built-in integral type (where == is used for the comparison), for each floating-point type (where comparison is with respect to a delta rather than strict equality) and for object types (where the equals method is used). So, although an intuitive interface to use, it is a shopping list to implement and document, involving no small amount of copy-and-paste duplication. To provide assertNotEquals would involve providing the same number of overloads again, along with the associated implementation, documentation and duplication. One could make a case that this would bloat the interface and make life for the implementer more tedious. It is certainly not an exciting task, but the question is on which side of the interface boundary should the slog and repetition occur? Is it the implementer’s responsibility or the interface user’s problem? Put like that, it seems clear that the convenience of an interface should favour its user over its implementer – write once, right for many. What about the question of bloat? One of the guidelines for effective interface design is that an interface should be concise. However, concise is not necessarily the same concept as short: to be concise means to be both brief and comprehensive. The measure of an interface is not necessarily in the number of methods it defines, but in the number of ways it can be used. So, although there are many assertEquals overloads, there is only really one assertEquals concept and only a couple of ways of calling it, so the usage is simple even if the actual Java method listing is long. Taken from this perspective it is clear that the omission of assertNotEquals is more of a pain than its potential inclusion. Taken over time, it takes longer to discover and explain its absence than to include and use it. Note that little or no explanation is required for such opposites: if you know what assertTrue does, then you know what assertFalse does; if you are told what assertSame does, you don’t need to be told what assertNotSame does. It is interesting to note that as JUnit has evolved, its assertion interface has become more symmetric. JUnit version 3.8 introduced assertFalse to pair with assertTrue, an obvious completion. assertTrue was introduced in version 3.7 to replace the assert method, which clashed with the keyword of the same name introduced in Java 1.4. However, even before Java 1.4 forced the issue in favour of a naming convention that threw the question of symmetry into sharp relief, an astute interface designer might have pondered the absence of assertNot as a partner for assert. Of course, not every assertion has an implied symmetry: JUnit’s unconditional assertion, fail, has no obvious complement. The absence of failure defines success – likewise, “if we do not succeed, then we run the risk of failure”, to quote Dan Quayle, the former US vice president, insightful logician and orthographer extraordinaire. Providing, or indeed Symmetry has something to offer the world of software. Kevlin Henney stands some interfaces in front of the mirror to see what’s missing OPPOSITES ATTRACT PROGRAMMERS’WORKSHOP KEVLIN HENNEY 48 APPLICATION DEVELOPMENT ADVISOR Facts at a glance • A symmetric pair of methods represent some opposite aspect. • The completeness of an interface can sometimes be considered in terms of its symmetry. • Symmetry, or its absence, can affect ease of use. • But not everything is symmetric – that would be forced and boring.
  • 2. requiring, a succeed method would run the risk of being both odd and awkward. Looking back at the Java RecentlyUsedList interface described in the previous two columns3, 4 , the most obvious asymmetry is the absence of an isFull query: interface RecentlyUsedList { boolean isEmpty(); int size(); int capacity(); void clear(); void push(String newHead); String elementAt(int index); ... } Just as list.isEmpty() more accurately captures the essence of list.size() == 0, list.isFull() would better express the intent of list.size() == list.capacity(). The ordering discipline encapsulated by a recently used list ensures that the most recently pushed is at the head and the least recently pushed value is last. The use of the push terminology suggests perhaps a pop method could be useful, losing the least recent entry. Whether or not one chooses to include these additional features, for convenience or capability, symmetry has certainly helped highlight them as considerations: interface RecentlyUsedList { boolean isEmpty(); boolean isFull(); int size(); int capacity(); void clear(); void push(String newHead); String pop(); String elementAt(int index); ... } The symmetry between push and pop is emphasised in their respective input and output. However, symmetry in code tends to be local, informal, evocative and sketched; it is rarely a global, formal, binding, mirror-perfect relationship. For example, there is no precondition on push, but pop cannot be called on an empty list; a successful pop always changes the visible state of the list, whereas a push of the most recently used item will leave the list unchanged. Reasonable asymmetry Of course, it is easy to become overly enchanted by symmetry. For example, having a habit or working to a guideline to provide a setter with every getter. Not only is this not a good idea, it is actually quite a bad one7 . Restricting object mutability either to full immutability – whether by copy, by class or by const8 – or to a few well- defined and well-motivated state- modifying methods is a more reasoned and less error-prone path to take. It is possible to query an entry in the recently used list by index, but not to set one by index. This is quite reasonable: setting a value directly would defeat the ordering discipline that is the whole point of a recently used list. It also leads to some interesting questions concerning one of the other invariants that govern the data structure: entries are unique. What would happen to the data structure if an entry were set, by index, to the value of an existing entry? There are many possible interpretations and responses, but few are worth pursuing. Such behaviour is outside the scope of a recently used list. The perceived requirement demands either a revisit or another solution. Scope creep often arises because such questions are answered in code rather than unasked. A more reasonable symmetry Conversely, a reasonable guideline is that if you have a setter, there should probably be a corresponding getter. To be more precise, if an object has an attribute, either conceptual or physical, that can be modified by a method, there should be some way of querying that attribute. Failure to do so leads to write-only attributes, which can be frustrating to use and awkward – or impossible – to test. For (counter)example, Java’s ArrayList class has an implied attribute that describes its current capacity, which is how many elements it can hold without automatically resizing, as opposed to its current size, which is the number of elements it currently holds. The capacity defaults to 10 on creation, unless it is specified directly as a constructor argument, and can be specified explicitly using the ensureCapacity method or trimmed to the current required size using trimToSize. The documentation talks about the capacity and how to change it, and the concept is visible in the interface, but there is no way to find out what it is. This means that the capacity is modifiable but unobservable, so the capacity-related operations are untestable: how would one write an assertion to confirm that the default constructed capacity was in fact 10? This may at first seem academic: testing the correctness of ArrayList is surely Sun’s problem, so there is no need to worry about the issue. However, it is the design principle at stake, not the specific example: there ought to be a test somewhere – within or without Sun – so what would it be? It is interesting to note that ArrayList’s less sophisticated, less well reasoned and less focused predecessor, Vector, offers the capacity query in question. Write-only attributes can be quite subtle, and it is easy to miss them, especially if you are the implementer. Proximity to the implementation can make it hard to share the interface user’s perspective. A critical eye – yours or someone else’s – or a test- driven approach6, 9 can help to tune into this line of symmetry. s References 1. Kevlin Henney, “Five Possible Things Before Breakfast”, artima.com, June 2003, www.artima.com/weblogs/ viewpost.jsp?thread=5432 2. Kevlin Henney, “Factory and Disposal Methods”, VikingPLoP 2003, September 2003, available from www.curbralan.com 3. Kevlin Henney, “Form Follows Function”, App Dev Advisor, March 2004. 4. Kevlin Henney, “Conventional and Reasonable”, App Dev Advisor, May 2004. 5. JUnit, available from http://junit.org 6. Kevlin Henney, “Put to the Test”, App Dev Advisor, November 2002. 7. Kevlin Henney, “The Good, the Bad, and the Koyaanisqatsi”, VikingPLoP 2003, September 2003, available from www.curbralan.com 8. Kevlin Henney, “Objects of Value”, App Dev Advisor, November 2003. 9. Kent Beck, Test-Driven Development by Example, Addison- Wesley, 2003. KEVLIN HENNEY PROGRAMMERS’WORKSHOP JULY-AUGUST 2004 49