intcreateProcess();// Which one is correct? errorCode =createProcess() processNumber =createProcess() processCount =createProcess() createdInMillis =createProcess()
Example: Bad: Method doing more than one thing
// Are the lines in the proper order?publicsynchronizedvoidflush() throws IOException {getContentBuffer().flush();IOUtils.copy(newStringReader(getContentBuffer().getBuffer().toString()),getBufferedWriter());getBufferedWriter().flush(); contentBuffer =newStringWriter();}
Example: Good: Methods doing one thing
// Method complies with the contract@Override// This is also important, not only for the compilerpublicsynchronizedvoidflush() throws IOException {flushMyBuffer();getBufferedWriter().flush();}privatesynchronizedvoidflushMyBuffer() throws IOException {contentBuffer.flush();IOUtils.copy(newStringReader(getContentBuffer().getBuffer().toString()),getBufferedWriter()); contentBuffer =newStringWriter();}// Now it is clear that it has two buffers. Is is a good solution?// Clean code is not the final goal, it is a way to the goal:// is the code correct?
Example: Bad: Method doing more than one thing (from the book)
// It does three thingspublicvoidpay() {for (Employee e : employees) {if (e.isPayday()) {Money pay =e.calculatePay();e.deliverPay(pay); } }}
Example: Good: Methods doing one thing (from the book)
Example: Bad: Side effect: modifying the input parameter
// Incorrect nameprivateSelectedDirectionDTOcreateSelectedOption(OptionDTO option,String fareFamily) {SelectedDirectionDTO so =newSelectedDirectionDTO();so.setId(option.getId());so.setOrigin(option.getOrigin());so.setOriginCountry(option.getOrginCountry());so.setDestination(option.getDestination());so.setDepartureDate(option.getDepartureDate());so.setDepartureTime(option.getDepartureTime());so.setArrivalDate(option.getArrivalDate());so.setArrivalTime(option.getArrivalTime());so.setMultipleOrigin(option.isMultipleOrigin());so.getFlights().addAll(option.getFlights());// Non-standard TODO comment// Not informative comment//FB_TODO: the code from here might need changes// Negative condition first: harder to understandif (!moreOptions) {// Inline implementationfor (RoutingFareDTO cFare :option.getFares()) {if (routingFareMatches(fareFamily, cFare)) {so.setFare(cFare); } } } else {// Inline implementationString fam =famMoreOptionMapping.get(fareFamily);if (fam !=null) {for (RoutingFareDTO fare :option.getFares()) {if (fam.equalsIgnoreCase(fare.getCompartment())) {so.setFare(fare);// Modifying the input parameter!so.getFare().setFareFamily(fareFamily); } } } }return so;}
Avoid Bad Input Parameter Types
Object
String for non-textual types
boolean for switches - use constants or enum instead
Program to Methods
Stateless, independent methods:
Prefer return values to modifying input variables
Prefer methods that depend only on the input parameters -No configuration parameters or data mining inside
Independent = easily testable
At the end of the method calls there should always be a method that depend only on the input parameter and whose only result is the return value (or exception).
Overloading
Use overloading only for convenience
For example for default values
Do not use it for hiding differences
They should call each other - code smell if they don't
Hiding
Hide irrelevant details in a separate method
Do not hide relevant details in a separate method
Example: Bad: Overloads and Hiding
// Overloads doing different things// relevant details are hidden (what lists are created)List<Integer> scores =initScores(10,0);List<Integer> scores =initScores(10);
Example: Good: No overloads and Hiding
// Method intention is expressed in their names// only irrelevant details are hidden (how lists are created)List<Integer> scores =createListWithEqualNumbers(10,0);List<Integer> scores =createListWithDifferentNumbers(10);
Two types of methods
"Coordinator" or "orchestrator"
"Technical" or "Algorithm"
Example: Good: Types of methods
// Orchestrator method - Easy to read - Business logicpublicvoidmodifySomething(Something s) {s.setAnything( s.getThis(),s.getThat() );if( s.isBig() ) {s.setSomethingElse( DEFAULT_SOMETHING_ELSE ); }}// Algorithm method - Easy to testpublicAnythingcalculateAnything(Thisthis,That that) {returnthis.getCount() *that.getSize();}
How to use these types:
Do not mix business lines with technical lines
Do not pollute the code with technical details
Hide irrelevant details
Do not hide relevant details
Example: Bad: Pollution by repeating irrelevant technical details