Fight Complex Software (And Win) | How to Name Methods | The List of Method Types
The Worst Problems Look Like Solutions
Complex software looks like a solution. Problems that are hard to root out often have this trait? And when problems look like solutions, their solutions invariably look like problems. The 7 Biggest Problems that lead to unmanageable software spills the beans.
The 7 Biggest Problems Leading to Unmanageable Software
Problem 1 » Software developers still wear “lines of code” as a badge of honour. The more the merrier. Code lines look like solutions so lots of code looks like the solution to lots of problems. That’s problem 1 in the fight against complex software.
Problem 2 » If code to print “Hello World” looks simple – that’s good. If code to solve a Rubik’s Cube looks complex – that’s good too! Solving a Rubik’s Cube fast is complex so how can anyone complain that the code for doing a complex thing is complex. That’s problem 2 in the fight against complex software.
Problem 3 » You get less bugs, less unwanted side effects, when the person changing software is (A) clever and (B) has lots of experience evolving that software — this looks like a statement of fact, a truth, not a problem. That’s problem 3.
Problem 4 » Who (or what) do you go to want to discuss the impacts of a potential change you plan to make? You go to the clever person who has lots of experience evolving that software. Again, that just seems obvious. That’s problem 4.
Problem 5 » When a bug appears someone goes into the debugger and spends time tracking down the problem. Hooray they find the problem. Suppose someone spent more time tracking down the problem – finding problems fast seems good, finding problems slowly – not so. That’s problem 5.
Problem 6 » Introducing bugs when fixing bugs sounds like a problem. No one (in their right minds) praises the developer who introduces new bugs when fixing them, over and above a developer that does a clinical job. That’s problem 6.
Problem 7 » Quality, purpose and load. A medieval king judging the quality of a defence (be it a wall, a moat, a catapult, a gate) would consider the enemy – how much the enemy could throw at the defence or how much the defence needed to throw at the enemy. A gate in the outer wall needs to be tougher than a gate to the stables. After 100,000 miles the engine on a BMW is still in its element – the engineers spend time on the engine – they understand usage. A BMW is unlikely to be strapped onto a catapult and thrown at an advancing enemy. Quality costs – if all the software you write is of “even quality” – the parts of the software that are buffeted not just by usage, but by change requests (bugs, enhancements, new features, optimizations …). You don’t often hear software developers saying – I’m going to rush through this bit and then do a great job on that bit – I’ve never heard that – have you? That’s problem 7.
The worst problems look like solutions!
Why Use Method Naming Conventions
The time spent reading code is 7 times longer than the time spent writing it, assuming the software is successful.
That’s why method names count for a lot. They convey the essence of a method. One glance – and the method name should tell you whether this is the method you are looking to use – or to investigate.
The 10 Places a Method Name Pops Up In
You don’t just see method names in Java code – you also see them in javadocs (documentation), listed as part of a classes high level structure, in code completion popups in your IDE (Eclipse, IntelliJ, …), in JUnit tests (eg calculateSalary becomes testCalculateSalary in your JUnit tests, in exception traces (stack trace) when code fails, in dependency injection and other property files (eg Spring properties), in JavaBean contexts like in a JSP file, a Hibernate mapper, in XML Parsers and other callback software configuration files, in test coverage reports, in analytics packages and more besides.
Method names are everywhere – get it right – and the software will be easily readable, reusable, testable, and refactorable.
Method names are part of your toolkit for tackling software complexity (either prevention or cure). Method names are everywhere – they speak volumes – so it is vital that everyone in your team understands how to name a method.
How to Name a Method (Method Categories)
The way you name a method boils down to what the method does (not how it does it). If you’ve named a class well, the next most important thing is to get the method names right. How?
Let’s classify methods. Method names follow a convention that depends on which category (type) – the method subscribes to.
The Types of Method
- constructors and create methods – these are factory methods that give birth to objects
- getters and setters – query or set data attributes states
- counting methods – counter increments and queries to ascertain count value
- invoke methods – invoke a chunk of processing
- boolean methods – is it true, did he/did she, can you, can it, have you, has it, has she
- import export methods – imports pull into an app’s auspices, exports do the reverse
- finder methods – imply extra effort –
- find thing by – expect one thing by primary key
- find plural – expect many to pass filter
- type binding methods –
Date getDateFromString("05 Feb 2020")
- explicit conversion –
float getFahrenheitTemperature( int centigradeTemperature )
- conversion methods –
float getFahrenheitTemperature( int centigradeTemperature )
- group by methods – are frequency distribution methods that return a map
- initialize (setup) methods – get things ready (eg constructors and factory methods) – name with init, setup
Write important words first – when naming a method the first word should differentiate the method to one (or at least a handful of types). That tells the reader whether they want to read any more. This follows the EXIT EARLY strategy.
The name getFahrenheitTemperature is better than getTemperatureInFahrenheit because Fahrenheit is the more important word. When a reader sees Fahrenheit they already think of temperature.
The Do One Thing Strategy
A method must explicitly do one thing and that thing must be obvious from the method name. The first word tells us the type of behaviour (see the method types list) and the other words follow a pattern. If developers follow the pattern then you won’t need to look at the argument list – the javadocs nor the method implementation. You’ll know if this is the method you are looking for or not.
If you are changing the software or using it yes – you’ll need to look at the argument list and javadocs, but if you are scanning – the method name should be enough.
Methods should do one thing (and one thing alone). Complex software continually breaks this rule.
Do one thing” vs “Do very little”
“Today I will do just 1 thing” – lazy is what you are thinking?
If winning 10,000m Olympic Gold is that thing – then that one thing stops being small – that one thing is an amalgam of a lot of detail – the culmination of years, perhaps even a lifetime of work.
These methods do one thing. Our brains relate “do one thing” with “do almost no-thing”. Zero is but a step away from one – surely?
See – solving the Rubik’s Cube is doing one thing – one thing does not mean trivial or small. Searching Google may be one line in your software – but a gargantuan array of behaviour and data is marshalled and brought into play.
Doing one thing is means exactly that! Do not let your mind draw conclusions and inferences about the nature of that thing. Zero can be light-years away from one.
How do I know my method does 1 thing?
How do I know if my method does one thing? The list of method types covers everything your method could possibly do (in the whole wide world). Your method, any method, can realistically do a couple of dozen things at the most.
Stick to those couple of dozen things and everyone will immediately understand what your method does.
The Exit Early Strategy
You want to give as much information as early as you can so the reader does not need to MINE deeper.
Give info in javadoc so reader does not need to go to code.
Give info in class name then method name so reader does not need to drill down.
Give info with guard clauses to prevent nested conditionals and keeps code flat
Give info with explaining method – refactor out small code chunks and give it a great name that explains what it does (and what it doesn’t do)
No She Didn’t?
All I want is a simple Yes or No answer – is that too much to ask? Write down speech and you will see statements that are questions and questions that are statements.
- Oh no she didn’t! is actually a question and
- Have you gone completely bonkers? is a statement
Booleans are big in life and methods that return a Boolean account for the lions share in the list of method types.
That’s why the method naming convention begins with the indefatigable and ubiquitous Boolean.
Method Naming Convention
Boolean Methods – True or False?
Boolean methods answer in one of two ways – either in the affirmative or otherwise. In great software little things convey a lot – so when naming boolean methods (the littlest of the lot) – you must make sure they begin with
- can – canVerb canRun, canJump, cannotHide
- has – hasThisFeature hasTheAbilityTo…
- is – isTheBestAndBrightest
- isCompatibleWith – are two things compatible, interchangeable, interoperable
- contains – Collection.containsThisThing( Thing )
- containsAll – Collection.containsAllTheseThings ( Collection<Thing> )
- cannot – Thing.cannotDoThisVerb (cannot run, jump, hide …)
How you think of an object is the bigger picture here. An object
- has features – person isRich()
- has attributes – person hasBlueEyes
- can behave a certain way – bird canFly() plane canFly()
- is made up of objects – person hasChildren() car hasEngine()
- can delegate queries to another object – Classroom.getPerson ( Teacher ).getName()
- can delegate queries about a collection – Classroom.getPupils().count()
Think of objects as having, features, attributes and behaviour.
Conversion Methods Explicit and Implicit
Methods should do one thing (and one thing alone). Complex software continually breaks this rule. Now conversions – when the one thing your method does is convert – that is a good start – but how can we make it better?
Conversion Methods – How to Improve
1 – Refactor – rename conversion methods to beging with convert…
2 – Refactor – replace explicit conversion methods with implicit conversion methods
3 – Refactor – rename implicit conversion methods to use the getThisAsThat pattern
3 – Refactor – move conversion method to constructor
Did You Know – Constructors are Converters
Did you know that most Constructors and Create methods are actually converters (conversion methods)?
- new String( char characterArray) – converts a character array into a string
- new ArrayList( Set<String> stringSet ) – converts a set into an ordered list
- new File(URI fileUri) – converts a filepath into a File
The Oracle Documentation for the above file constructor says that Creates a new File instance by converting the given file: URI into an abstract pathname.
Whenever a Constructor takes an argument – you are likely looking at a hidden conversion method.
Motivation (What’s Your Problem)?
– conversion methods have a twin (implied or real) – convertToFahrenheit(int centigradeTempToConvert) twin is convertToCentigrade(int fahrenheitTempToConvert)
– explicit conversion methods accept an argument to convert – convertToFahrenheit(int centigradeTempToConvert) or convertToCharArray(String stringToConvert)
– explicit conversion methods switch the method name and argument name (parity) between one twin and the other
Refactor Step 3 – Replace explicit conversions methods with implicit conversion methods
Why Do This? – Motivation
1 – explicit converters are (or may as well be) static methods Temperature.convert( float tempToConvert ) – this bypasses object behaviour and breaks encapsulation
2 – implicit converters have NO arguments – simple to read, simple to change
3 – clutter – explicit converters have EITHER 2 methods with 1 argument OR 1 method with 2 arguments
4 – confuse – converters have EITHER 2 methods OR 2 arguments – (at least) – look at this call – getTemperature(float temperature, true)
Look at this call – getTemperature(float temperature, true) – What does true mean? Should the 1st arg be in Fahrenheit or centigrade? Let’s replace this with an implicit get As method call on a real (not static) temperature object.
These are Bad (Explicit Methods)
Temperature.getTemperature(float temperature, true)
Temperature.convertTemperature(float temperature, true)
These are Better (Implicit Methods)
Methods that return a number – How Many? How Much?
Counting methods always return an integer (int) – however methods that return an integer are not always counting methods.
Methods like getHashcode(), multiplyBy5( integer ) or totalInvoiceItems( Collection<Invoice> ) return an integer but they are not counting methods. Counting methods tell you how many – and you should name them like this
- count – countOfHousesInStreet
Methods that return numbers can be
totalPrice – sums 2 multiplied attributes like quantity and itemPrice in a collection)
sumPupilsInEachClass sums one attribute from a collection Class.countOfPupils
Group By Methods – frequency distribution
A group by method returns an integer map that states how many times something occurred in something else.
The method naming pattern is groupThisByThat
Example Map<Integer, Integer> groupWordsByLength()
The call newsArticle.groupWordsByLength
The map will look something like this
|Word Length (key)||Count|
A kids story above contains 8 words that have 1 letter, 19 words that have 2 letters, 14 words that have 3 letters and so on.
Do Methods – The Imperative
The imperative tense is not asking – it is telling. Do this now! Pass me the milk! Stop talking! Eat your breakfast! Walk the dog! Untie my shoelaces!
We expect Do methods to change state! Something will get done – things will be different after it is done.
To qualify as “Do” – a method
- is expected to change state
Do methods begin with imperative. Which method is NOT a doNow() imperative?
You are right! – countChickens is not a doNow() method because it does not change state. Count chickens is imperative, grammatically speaking, but it is not expected to change state.
expected to change state – What does it mean?
If a method changes state during its main use case flow of events, it is a doSomething() method. It may not change anything during alternative and/or exceptional flows.
Note that the converse – methods not expected to change state (like countChickens()) – should NEVER change state even on alternate and exceptional use case flows.
Also “changing state” excludes side effect actions like logging or opening a file for reading.
Expected to change state me (if it follows it’s main use case flow of events and not alternative flows that may or may not change state).
You can optionally start these method names with “do”