Download as pdf or txt
Download as pdf or txt
You are on page 1of 74

Enterprise Java Training

The Art of Clean Code


Victor Rentea
30 may 2017, Sofia © Copyright Victor Rentea 2017

VictorRentea.ro
victor.rentea@gmail.com
@victorrentea
VictorRentea.ro
Agenda
 Introduction Why ?!
 Names The power invested in you
 Functions SRP
 Classes The OOP utopia
 Comments Incompetence
 Clean Lambdas Handling a lightsaber
2 VictorRentea.ro
Victor Rentea
Consultant, Technical Lead
Lead Architect for major IBM client Independent Trainer
1000+ devs. 1500+ hrs. 5 yrs.
Clean Code Evangelist
Spring, JavaEE, JPA/Hibernate
Speaker Clean Code, Architectures
Design Patterns
TDD, Coach, Coding Dojos
Java Performance, more...
victor.rentea@gmail.com @victorrentea VictorRentea.ro
3 VictorRentea.ro
Introduction

Clean Code …
Bjarne Stroustrup
…does one thing well inventor of C++

Grady Booch
…reads like well written prose inventor of UML
Michael Feathers
...was written by someone who cared Working Effectively
with Legacy Code
...when each method you read turns out to be
Ward Cunningham
pretty much what you expected inventor of Wiki, eXtreme Programming

Anyone can write code that a computer understands,


Martin Fowler
but few programmers know how to write author of Refactoring
code that a human can understand
4 VictorRentea.ro
The Principle of Least Astonishment
The code is pretty much what you expected

wtf/min

code quality meter


5 VictorRentea.ro
Introduction

Why Clean Code ? 80% of the total


True cost of software = its maintenance
Why so much !?!
Cause we get slower, as the code degrades

6 VictorRentea.ro
Why Clean Code ?
We READ 10x more time than we WRITE
 Make it more readable, even if it’s harder to write

Boy scout rule


Always check in cleaner code than you found

7 VictorRentea.ro
8 VictorRentea.ro
Today, I stopped refactoring.
Today, my application became Legacy.

9 VictorRentea.ro
Agenda
 Introduction
 Names The power that YOU have
 Functions
 Classes
 Formatting & Comments
 Clean Lambdas
11 VictorRentea.ro
Names

With Great Power


Comes Great Responsibility
- SpiderMan

12 VictorRentea.ro
Names

“Well Written Prose”

Functions are verbs


product(), transaction()
searchProduct(), sendTransaction()

Boolean names should answer yes/no


isGoldClient(), areHostsValid()

?! ?! ?!
green 17 “Mike”

13 VictorRentea.ro
Names

“Well Written Prose”

Classes are nouns


Customer, OrderDetails, OrderFacade

Avoid meaningless names


OrderInfo, OrderData vs Order

Delete the interfaces


ICustomerService, OrderServiceImpl
14 VictorRentea.ro
Delete the interfaces
except:

Remoting/API
your-app-api.jar

Strategy Pattern®
Select implementation dynamically at runtime

Dependency Inversion But that’s


Implemented in lower-level modules another talk

15 VictorRentea.ro
Names

How do you understand a function ?

- You read the /* dusty old comment */ ?


- You hunt down the code calling it ?
- You decrypt its implementation ?

You should NOT need to do that!


Make the name speak for itself !
16 VictorRentea.ro
Make the name speak for itself !
You think you found a better name?
Yes, you did!
OMG! It’s impossible!
I CAN’T be smarter
than The Elders!!

Rename it !
It takes seconds with an IDE
(and rarely fails: XMLs, reflection,…)

17 VictorRentea.ro
Names

There are no perfect names !


There are only two things
hard in programming:
Cache Invalidation and
Naming Things

Continuous Renaming
Rename it !
(as you learn the application)

The team will be grateful!


Yourself will be grateful, in 3 months!
18 VictorRentea.ro
Continuous Renaming
19 VictorRentea.ro
Names: Several Guidelines

Names should be …

Pronounceable
int getinvcdtlmt()
int getInvoiceableCreditLimit()

Avoid abbreviations !
Unless it’s a basic business concept, like “VAT”

20 VictorRentea.ro
Names should be …

Consistent
.find…() .fetch…() or .get…() ?
Stick to naming conventions

Unique
Synonyms confuse.
Don't use buyer or client to refer to a customer

21 VictorRentea.ro
Business-IT Gap

22 VictorRentea.ro
Agenda
 Introduction
 Names
 Functions Single Responsibility Principle
 Classes
 Formatting & Comments
 Clean Lambdas
26 VictorRentea.ro
Functions

A function should do one thing,


it should do it well,
and it should do it ONLY
Uncle Bob

They should be

Small VictorRentea.ro
27
Functions

Functions Should be Small !!


How small ?
Why so small ?!!

5 lines
(by any means, smaller than a page of your IDE !)

To be sure that they do just 1 THING


wtf/min
Now really, what CAN you do in 5 lines ??

So you CAN find a good name for it


28 VictorRentea.ro
Functions
if
for

The function is a landscape if


i
f
if

for
Easy to remember by its author
But for the team, else

if
it's like wilderness
for if
if

if you don’t… for

29 VictorRentea.ro
Change Request #323
…, boolean cr323)

What do you do ?
EXTRACT
METHODS

if (cr323) {
doOtherStuff();
}

30 VictorRentea.ro
Functions

Why do small functions scare us?


Performance ?

NO!
Smaller methods run faster !
(get faster)
Just google “Just-In-Time Compiler Optimizations”

31 VictorRentea.ro
Performance ?

Measure, Don’t Guess®


– Kirk Pepperdine

Premature optimization is the root of all evil


– Donald Knuth

32 VictorRentea.ro
Why do small functions scare us?
Instead of a familiar landscape,
else
for if

I’m now juggling with tons of small functions


I can’t even recall all their names

but,
The Team will thank you !
Even you will be grateful, in 3 months :)

33 VictorRentea.ro
No boolean params => 4
(usually 3)
removeOrders(customer, false, true);
= laziness/fear/rush = legacy

No nullable params => 2


if (customer != null) {…} else {…} What about
invalid data?

37 VictorRentea.ro
Functions

NULL
(corrupt data)
WARS
File

Web Avoid returning null


Service
Wrap it in an Optional<>
Throw exception

Defensive Programming
Queue Thoroughly check data
DB only at the boundaries
38 VictorRentea.ro
Unchecked exception
Exceptions won the War !
try
throws
catch (Exception t) {/*Luv U!*/}

We Runtime Exceptions
(‘cause we don’t see them)

My preferences:
Global exception handler try {…} catch (Exception e) { log(e);}

Nice (i18n) user messages: enum new MyException(ErrorCode.USER_EXISTS);

New Exception only for selective catch catch (MyTimeoutException e) {retry();}

39 VictorRentea.ro
How to write such Functions ?

Continuous Refactoring
all tests
You are not done when the codepass ! working!
starts

It is then when you should


Clean Up your code !!
( IDEs help you a lot )

41 VictorRentea.ro
An else follows…
public List<Integer> stringsToInts(List<String> strings) {
if (strings != null) {
List<Integer> integers = new ArrayList<>();
for (String s : strings) {
integers.add(Integer.parseInt(s));
}
return integers;
} else {
return null;

}
}
How to simplify it ?

42 VictorRentea.ro
public List<Integer> stringsToInts(List<String> strings) {
if (strings == null) {
return null; Early Return
}
List<Integer> integers = new ArrayList<>();
for (String s : strings) {
integers.add(Integer.parseInt(s));
}
return integers;
}

Less TABs => easier to read


Fail the build if you detect 3+ TABs in a new method
43 VictorRentea.ro
How to refactor God Methods
Hint of 100-1500 lines ?
A class should have less
than 200-300 lines

Extract Method Object refactor


You make it a class
44 VictorRentea.ro
Extract Method Object refactor
public String doComplexStuff(String text) { public class DoComplexStuffCommand {
Set<String> words=new HashSet<>(); private final String text; STATEFUL
int totalWords = 0; private Set<String> words=new HashSet<>();
int totalPhrases = 0; private int totalWords = 0;
StringTokenizer tokenizer = … private int totalPhrases = 0;
while (tokenizer.hasMoreTokens()) { private StringTokenizer tokenizer;
String next = tokenizer.nextToken(); …
public ExtractedMethodCommand(String t) {
if (…) {
this.text = t;
for (…) {…}
tokenizer=new StringTokenizer(text," ");

}
} else {
Extracting a method may public String execute() {…}

}
require many parameters,
} output parameters These methods use instance fields,
} // line 534  or be even impossible } and take no/fewer arguments

String result = doComplexStuff(”bla”); = new DoComplexStuffCommand(”bla”).execute();

45 VictorRentea.ro
Agenda
 Introduction
 Names
 Functions
 Classes The OOP utopia
 Formatting & Comments
 Clean Lambdas
46 VictorRentea.ro
struct
(remember the C language ?)

47 VictorRentea.ro
struct
Data structures
=classes that expose all their state
public class SimpleImmutableStruct { public class PhoneBookEntryDTO {
private final String firstName; private String firstName;
private final String lastName; private String lastName;
private String phoneNumber;
public SimpleImmutableStruct(
String first, String last) { public String getFirstName() {
public class PhoneBookEntryDTO {
this.firstName = first; return firstName;


public String firstName;
this.lastName = last; }
public String lastName;
} public void setFirstName(String first) {
public String phoneNumber;
this.firstName = first;
}
public String getFirstName() { }
return firstName;
} public String getLastName() { … }
We getLastName()
public String Immutable {Objects: public void setLastName(…) { … }
- If created valid, remain so
return lastName;
} - Thread safe public String getPhoneNumber() { … }
public void setPhoneNumber(…) { … }
} - Safe to put in Tree*/Hash* }
48 VictorRentea.ro
OOP
49 VictorRentea.ro
Expose Behavior, not data
Data is an implementation detail: it WILL change
car.engineStarted=true
car.setEngineStarted(true)
car.startEngine()

Information Hiding
OOP Tell as little as possible
car.getGasolineInLiters()
car.getPercentageFuelLeft()
car.getEstimatedRemainingKm()

Allowing the implementation to evolve


without breaking your clients
50 VictorRentea.ro
But at work
we don’t do OOP, do we ?

In our Enterprise App,


we write procedural code

51 VictorRentea.ro
What’s the goal of an Enterprise Application ?

(usually)
To automate an existing business process.
Existing procedures.

Procedural Code
52 VictorRentea.ro
Procedural Code
Lots and lots and lots and lots and lots of it…

How do we organize it, to


Keep It Short & Simple ?

53 VictorRentea.ro
Procedural Code
Keep It Short & Simple !!

We distribute logic in many classes:

Classes as containers of logic


(in enterprise applications)
54 VictorRentea.ro
So,
Do we ever do OOP?

Yes!
When writing

Libraries and (mini) Frameworks


Versioning Hell
mycorp-commons- .jar

55 VictorRentea.ro
Agenda
 Introduction
 Names
 Functions
 Classes
 Formatting & Comments
 Clean Lambdas
63 VictorRentea.ro
64 VictorRentea.ro
65 VictorRentea.ro
At work, it’s not Matrix, you know…
It’s Team Work

66 VictorRentea.ro
Don’t Code!
Communicate !

67 VictorRentea.ro
Don’t Code! Communicate !
Respect your readers
Details matter: 10x more reading, remember ?

Write Literature
Always the simplest code that works.
Never obfuscate

VictorRentea.ro
Tune your IDE
Learn those shortcuts !
Static imports
assertEquals(), when(), toList(), emptyList(),…

Default code blocks


catch(Exception e) { throw new RuntimeException(e); }

Super-Fast Deploy
Hot bytecode replace ?

70 etc... VictorRentea.ro
Formatting

Suggestions…
100-120 chars
public class SomeClass {

public void someMethod(…) {
5-10 lines 100-200 lines

never >1 screen
}
never > 500
… {
} }

2-3-4 chars / TAB? ? Spaces, code style, …


Team
71 VictorRentea.ro
Comments = Failures
Written proof of incompetence

Always before dropping a comment, and


Try to express it in code

Why do we hate comments ?


Comments LIE !
They inevitably fall out of sync with the code
/* very important comment from 10 years ago that tells that... */
72 VictorRentea.ro
Readable Constants public List<int[]> getCells() {
List<int[]> list1 = new ArrayList<int[]>();
- Instead of magic numbers for (int[] x : theList)
if (x[0] == 4) list1.add(x);

Explanatory Variables }
return list1;

- Name intermediary results


- Break multiline && public
publicList<int[]>
List<Cell> getFlaggedCells(){
getFlaggedCells(){
conditions || formulas List<int[]>
List<Cell> flaggedCells
flaggedCells == new
new A…L…<…>();
A…L…<Cell>();
for
for(int[]
(Cell cell
cell :: gameBoard)
gameBoard) {{
Explanatory Methods boolean isFlagged= cell[STATUS]==FLAGGED;
if (cell.isFlagged())
if (isFlagged)
flaggedCells.add(cell);
- "Encapsulate Conditionals"
} flaggedCells.add(x);
Split your methods } return flaggedCells;
- into many small functions }return flaggedCells;
with long descriptive names }

73 VictorRentea.ro
Bad Comments
Mumbling Position Markers
- Unclear! stream.close(); //////////////// Accessors ////////////////
} catch (IOException e) {
- Rush/lazy? // Give me a break!
- Forgotten?
} Commented-out Code
Don't read it. Just DELETE IT!
Git rocks!
Redundant
/** Returns the day of the month.
* @return the day of the month.
Non-Local
*/ Comment on that same line !! (±1)
public int getDayOfMonth() {

}
return dayOfMonth; DUH !! Over-involvement
Wiki article syndrome
/** Default constructor. */

74 VictorRentea.ro
Good Comments
Intent: WHY?(what?) TODOs
When the code just can't say it // TODO vrentea Fetch the order

specific algorithms: http://wiki... Assume ownership


bug workarounds: http://jira... Prepare for D-day

Clarifications Public API JavaDocs


to explain calls to a strange API For libraries/frameworks you write

Warning of consequences Legal


…=new SimpleDateFormat(…); // Not thread-safe // Copyright (C) 2013, …

75 VictorRentea.ro
Agenda
 Introduction
 Names
 Functions
 Classes
 Formatting & Comments
 Clean Lambdas
76 VictorRentea.ro
Clean Lambdas

Why Lambdas ?
They are cool

77 VictorRentea.ro
But is the Code Cleaner ?
(than in Java7)

78 VictorRentea.ro
Clean Lambdas

Expressive ?
.filter(MyObj::isActive)
or My own little
Clean Lambdas study
Cryptic ?
.filter(order -> order.getOrderLines().stream()
.filter(line->line.isActive()).findFirst().isPresent())
.map(Order::getOrderLines)
.flatMap(List::stream)
.filter(orderLine -> orderLine.getCount().compareTo(new BigDecimal(“2”))
.collect(groupingBy(OrderLine::getProduct,
groupingBy(line->line.getOrder().getPaymentMethod(),
summingInt(OrderLine::getCount);

79 VictorRentea.ro
.filter(order -> order.getOrderLines().stream()
Avoid breaking lines
.filter(line->line.isActive()).findFirst().isPresent())

.map(Order::getOrderLines)

.flatMap(List::stream)

.filter(orderLine -> orderLine.getCount().compareTo(new BigDecimal(“2”))

.collect(groupingBy(OrderLine::getProduct,

groupingBy(line->line.getOrder().getPaymentMethod(),

summingInt(OrderLine::getCount);

Clean Lambdas study


My own little

80 http://bit.ly/2dFf2fi VictorRentea.ro
Clean Lambdas

Encapsulate Predicates

Set<Customer> customersToNotify = orders.stream()

.filter(order -> order.getDeliveryDueDate().before(warningDate) &&

order.getOrderLines().stream()

.anyMatch(line -> line.getStatus() != Status.IN_STOCK))

.map(Order::getCustomer)

.collect(toSet());

81 http://bit.ly/2dFf2fi VictorRentea.ro
public static Predicate<Order> deliveryDueBefore(Date date) {
Local Variables return order -> order.getDeliveryDueDate().before(date);
}
Functions returning Predicates
Predicate<Order> needsTracking = order -> order.getPrice() > 1000;
Set<Customer> customersToNotify = orders.stream()
.filter(deliveryDueBefore(warningDate).or(needsTracking))
.filter(this::hasLinesNotInStock)
.map(Order::getCustomer)
.collect(toSet());

public boolean hasLinesNotInStock(Order order) { class OrderLine { ...


return order.getOrderLines().stream() public boolean isNotInStock() {
.anyMatch(OrderLine::isNotInStock); return status != Status.IN_STOCK;
} }
}
Helper methods in this:: Helper getters in entities
87 http://bit.ly/2dFf2fi VictorRentea.ro
Clean Code in Java8

Try some lib?


if checked Ex, >2 params
jOOL, vavr,…

For more, check-out the screen cast of my Clean Lambdas workshop


88 at Voxxed Bucharest 2017, on my website  VictorRentea.ro
Peer Review!
Pair Programming

89 VictorRentea.ro
Peer Review!
Pair Programming
90 VictorRentea.ro
Agenda
 Introduction
 Names
 Functions
 Classes
 Formatting & Comments
 Clean Lambdas
93 VictorRentea.ro
Key Points
Agenda

Stop
Introduction
Refactor = Start Legacy
 NamesExpressive Names
Refine
 Functions
Short methods
 Classes Objects or Logic Containers ?
Structs,
 Formattingare
Comments & Comments
Failures. Expressive code.
 Clean
Pair Lambdas is the way
Programming
94 VictorRentea.ro
Where
can I read
LET’S
more ?
How to PRACTICE
apply all !!!
this in my
legacy
code
??

98 ©
 http://literatejava.com/exception
s/checked-exceptions-javas-
biggest-mistake/
 http://stackoverflow.com/questio
ns/613954/the-case-against-
checked-exceptions
 7 Virtutes of a Good Object
 https://dzone.com/articles/the-
worst-mistake-of-computer-
science-1
 http://blog.8thlight.com/uncle-
bob/2012/08/13/the-clean-
architecture.html
 http://commadot.com/wtf-per-
minute/
 SOLID is WRONG:
https://speakerdeck.com/tastapo
d/why-every-element-of-solid-is-
wrong
 Depenency Injection leads to
Clean Code :
https://youtu.be/RlfLCWKxHJ0

99
Check out my tweets for more
VictorRentea.ro
Special Thanks to
JPoint Conference Team,
Ionuţ Chereji, Florin Diaconu
Victor Bucuţea, Ionuţ Scutaru
Laurenţiu Carată, Leonard Giura
Enterprise Java Training

The Art of Clean Code


Victor Rentea
30 may 2017, Sofia © Copyright Victor Rentea 2017

VictorRentea.ro
victor.rentea@gmail.com
@victorrentea
VictorRentea.ro

You might also like