SlideShare une entreprise Scribd logo
1  sur  69
Design principles 
presenter: Sergey Karpushin
2 
Agenda 
• Justification 
• DRY 
• SLAP 
• Single Responsibility 
• Open/Closed 
• Liskov substitution 
• Interface segregation 
• Dependency inversion
3 
Justification 1/4 
Where you spend time? 
Fixing tons of bugs Implementing new functionality 
How do you feel about 
new change requests? 
It’s ok, just need to make right 
design decision 
I’m scared! This will 
break something 
How complicated 
current codebase is? 
It’s large, but easy to understand 
and safe to change 
I need to expand 
consciousness to have a clue
4 
Justification 2/4 
Where you spend time? 
Fixing tons of bugs Implementing new functionality 
How do you feel about 
new change requests? 
It’s ok, just need to make right 
design decision 
I’m scared! This will 
break something 
How complicated 
current codebase is? 
It’s large, but easy to understand 
and safe to change 
I need to expand 
consciousness to have a clue 
Signal words: urgent, stress, overtime, chaos, more than 100 
open bugs, “who wrote this crap?”
5 
Justification 3/4 
Where you spend time? 
Fixing tons of bugs Implementing new functionality 
How do you feel about 
new change requests? 
It’s ok, just need to make right 
design decision 
I’m scared! This will 
break something 
How complicated 
current codebase is? 
It’s large, but easy to understand 
and safe to change 
I need to expand 
consciousness to have a clue 
Signal words: ahead of schedule, only 3 open bugs, thank you
6 
Justification 4/4 
OOD & other related principles 
• Takes time to understand and feel for the first 
time 
• Relatively easy to apply later
Disclaimer: 
NAMING CONVENTION
8 
Naming convention 
• Design principles are common for all Object-Oriented 
languages 
• Java naming conventions used within this presentation 
• Name example for interfaces, DTOs and “simple” 
classes: 
UserService 
• Name example for classes which implements interfaces 
UserServiceImpl 
• All variable and parameter names example 
camelCaseName
DON’T REPEAT YOURSELF
10 
DRY 1/15 
Don’t Repeat Yourself 
• Do not Repeat Yourself 
– Reuse your code, do not duplicate it 
– Assign clear names 
– Choose right location 
• Clear names and right location allows to 
identify duplicate candidates
11 
Don’t Repeat Yourself 
DRY 2/15 – reuse 
• Maintain “single source of truth” 
– Change once 
– Test once 
• Do not confuse with abstractions, it’s different
12 
Don’t Repeat Yourself 
DRY 3/15 – reuse 
• Same code in multiple places 
stmt.execute("SELECT name, email FROM users WHERE id = ?", id);
13 
Don’t Repeat Yourself 
DRY 4/15 – reuse 
• A change required? 
i.e. database field renamed 
stmt.execute("SELECT name, email FROM users WHERE id = ?", id);
14 
Don’t Repeat Yourself 
DRY 5/15 – reuse 
• A multiple changes required! 
stmt.execute("SELECT last_name, email FROM users WHERE id = ?", id);
15 
DRY 6/15 – reuse 
• What if code is in one place? 
getUserById(id); 
stmt.execute( 
"SELECT name, email FROM users WHERE id = ?", 
id); 
Don’t Repeat Yourself
16 
DRY 7/15 – reuse 
• Exactly! 1 change required. 
getUserById(id); 
stmt.execute( 
"SELECT last_name, email FROM users WHERE id = ?", 
id); 
Don’t Repeat Yourself
17 
DRY 8/15 – confusing w/ abstractions 
• Suppose we have Users and Articles 
getUserNameById(id); 
stmt.execute( 
"SELECT name FROM users WHERE id = ?", 
id); 
getArticleNameById(id); 
stmt.execute( 
"SELECT name FROM articles WHERE id = ?", 
id); 
Don’t Repeat Yourself
18 
DRY 9/15 – confusing w/ abstractions 
• Hey! It was a duplicate! We got rid of it! 
getObjectNameById(table, id); 
stmt.execute( 
"SELECT name FROM ? WHERE id = ?", 
table, id); 
Don’t Repeat Yourself
Don’t Repeat Yourself 
DRY 10/15 – confusing w/ abstractions 
19 
• Incoming change request: “Article name must 
be displayed along with author and date”
Don’t Repeat Yourself 
DRY 11/15 – confusing w/ abstractions 
20 
• Complete mess, this is what you end up with 
?!?!?!? 
getObjectNameById(table, id); 
stmt.execute( 
?!?!?!? 
"SELECT name FROM ? WHERE id = ?", 
id); 
?!?!?!? 
?!?!?!? 
?!?!?!?
Don’t Repeat Yourself 
DRY 12/15 – confusing w/ abstractions 
21 
• For abstractions recommended approach is 
– Write 
– Copy & Paste 
– Only then – extract abstraction
22 
Don’t Repeat Yourself 
DRY 13/15 – clear names 
• Q: How can I determine if name is “clear”? 
• A: If javadoc will look redundant 
• Q: How to pick clear name? 
• A: Write java doc, get essence of it, use as name 
• Q: It sometimes so complicated to pick short but 
still clear name! 
• A: Be honest with yourself, it happens rarely. In 
such case write descriptive javadoc
23 
Don’t Repeat Yourself 
DRY 14/15 – clear names 
An example 
• You can say almost nothing about it: 
String[] l1 = getArr(str1); 
• But this one is pretty descriptive: 
String[] fieldValues = parseCsvRow(csvRow);
24 
Don’t Repeat Yourself 
DRY 15/15 – right location 
• No one will guess that it might be here! 
package ru.it.projects.umms.dom.users; 
public class ArrayUtils { 
}
SINGLE LAYER OF ABSTRACTION 
PRINCIPLE
26 
Single Layer of Abstraction Principle 
SLAP 1/3 
• Single Layer of Abstraction Principle 
…for methods 
• Have common things with DRY, SRP, ISP 
• Basic idea is: 
– Do not write endless methods which logic is hard 
to follow. 
– All instructions for each method should operate 
on same level of abstraction and related to “one 
task”
27 
Single Layer of Abstraction Principle 
SLAP 2/3 (violated) 
private UserInfo retrieveUserInfo(String userToken) { 
String userTokenParts[] = userToken.split(":"); 
long userId; 
if (userTokenParts.length == 1) { 
userId = Long.parseLong(userToken); 
} else { 
if ("legacy".equals(userTokenParts[0])) { 
userId = Long.parseLong(userTokenParts[1]); 
} else { 
userId = Long.parseLong(userTokenParts[0] + userTokenParts[1]); 
} 
} 
String url = userServiceBasePath; 
if ("legacy".equals(userTokenParts[0])) { 
url += "/v1/getUserData?userId=" + userId; 
} else { 
url += "/v2/users/" + userId; 
} 
try { 
HttpResponse getResponse = client.execute(url); 
final int statusCode = getResponse.getStatusLine().getStatusCode(); 
if (statusCode != HttpStatus.SC_OK) { 
Log.w(getClass().getSimpleName(), "Error " + statusCode + " for URL " + url); 
return null; 
}
28 
Single Layer of Abstraction Principle 
SLAP 3/3 (following) 
private UserInfo retrieveUserInfo(String userToken) { 
long userId = extractUserIdFromToken(userToken); 
if (isLegacyUser(userToken)) { 
return retreiveLegacyUserInfo(userId); 
} else { 
return retreiveUserInfo(userId, extractUserDomainIdFromToken(userToken)); 
} 
} 
• The only concern: you’ll have more methods. 
Yes, but each of them is clear and damn 
simple to follow (thus maintain)
OPEN-CLOSED PRINCIPLE
30 
Open-Closed Principle 
OCP 1/11 – general idea 
Open-Closed Principle 
• Class should be 
– Open for extension 
– Closed for modification 
• Effects 
– Increased stability – existing code (almost) never 
changes 
– Increased modularity, but many small classes
31 
Open-Closed Principle 
OCP 2/11 – i.e. 
• Customer brings new user story: 
As the user I want to see results of past 
games. Let’s keep up with NHL & NBA games
32 
Open-Closed Principle 
OCP 3/11 – i.e. 
public class SportInfoParser { 
public SportInfo parseSportInfo(String[] sportInfoArray) { 
if ("nba".equals(sportInfoArray[0])) { 
NbaSportInfo nbaSportInfo = new NbaSportInfo(); 
Map<Long, Integer> scores = new HashMap<Long, Integer>(); 
scores.put(Long.parseLong(sportInfoArray[12]), Integer.parseInt(sportInfoArray[13])); 
NbaSportInfo.setScores(scores); 
return nbaSportInfo; 
} else if ("nhl".equals(sportInfoArray[0])) { 
NhlSportInfo nhlSportInfo = new NhlSportInfo(); 
nhlSportInfo.setSlapShotCount(1); 
return nhlSportInfo; 
} 
} 
}
33 
Open-Closed Principle 
OCP 4/11 – i.e. 
• Customer feedback: 
Thank you, it works well! 
• And brings another user story: 
As the user I want to see results of MLB games
34 
Open-Closed Principle 
OCP 5/11 – i.e. 
public class SportInfoParser { 
public SportInfo parseSportInfo(String[] sportInfoArray) { 
if ("nba".equals(sportInfoArray[0])) { 
NbaSportInfo nbaSportInfo = new NbaSportInfo(); 
Map<Long, Integer> scores = new HashMap<Long, Integer>(); 
scores.put(Long.parseLong(sportInfoArray[12]), Integer.parseInt(sportInfoArray[13])); 
NbaSportInfo.setScores(scores); 
return nbaSportInfo; 
} else if ("nhl".equals(sportInfoArray[0])) { 
NhlSportInfo nhlSportInfo = new NhlSportInfo(); 
nhlSportInfo.setSlapShotCount(1); 
return nhlSportInfo; 
} else if (sportInfoArray[0].equalsIgnoreCase("mlb")) { 
MlbSportInfo mlbSportInfo = new MlbSportInfo(); 
mlbSportInfo.setHits(Integer.parseInt(sportInfoArray[1])); 
mlbSportInfo.setRuns(Integer.parseInt(sportInfoArray[2])); 
return mlbSportInfo; 
} 
} 
}
35 
Open-Closed Principle 
OCP 6/11 – i.e. 
• Customer feedback: 
Why users see errors? I pay you for working 
app, not for errors! Make it work right till 
evening! 
• After debugging you found silly NPE mistake
36 
Open-Closed Principle 
OCP 7/11 – i.e. 
public class SportInfoParser { 
public SportInfo parseSportInfo(String[] sportInfoArray) { 
if ("nba".equals(sportInfoArray[0])) { 
NbaSportInfo nbaSportInfo = new NbaSportInfo(); 
Map<Long, Integer> scores = new HashMap<Long, Integer>(); 
scores.put(Long.parseLong(sportInfoArray[12]), Integer.parseInt(sportInfoArray[13])); 
NbaSportInfo.setScores(scores); 
return nbaSportInfo; 
} else if ("nhl".equals(sportInfoArray[0])) { 
NhlSportInfo nhlSportInfo = new NhlSportInfo(); 
nhlSportInfo.setSlapShotCount(1); 
return nhlSportInfo; 
} else if (sportInfoArray[0].equalsIgnoreCase("mlb")) { // NPE occured 
MlbSportInfo mlbSportInfo = new MlbSportInfo(); 
mlbSportInfo.setHits(Integer.parseInt(sportInfoArray[1])); 
mlbSportInfo.setRuns(Integer.parseInt(sportInfoArray[2])); 
return mlbSportInfo; 
} 
} 
}
37 
Open-Closed Principle 
OCP 8/11 – i.e. 
• You did small change, but whole class became 
unstable 
• OCP is violated - we modified existing code 
• How to make code open for extension? 
– Use inheritance 
– Use delegation/composition
38 
Open-Closed Principle 
OCP 9/11 – i.e. 
public class SportInfoParserDelegatingImpl implements SportInfoParser { 
private Map<String, SportInfoParser> parsers; 
public SportInfoParserDelegatingImpl (Map<String, SportInfoParser> parsers) { 
this.parsers = parsers; 
} 
public SportInfo parseSportInfo(String[] sportInfoArray) { 
SportInfoParser parser = parsers.get(sportInfoArray[0]); 
if (parser == null) { 
return null; 
} 
return parser.parseSportInfo(sportInfoArray); 
} 
} 
public class SportInfoParserMbaImpl implements SportInfoParser { ... } 
public class SportInfoParserNhlImpl implements SportInfoParser { ... } 
public class SportInfoParserMlbImpl implements SportInfoParser { ... }
39 
Open-Closed Principle 
OCP 10/11 – i.e. 
• You fixed bug and did refactoring to follow 
OCP 
• Customer feedback: 
Great, now it works well! Lets add support for 
WNBA!
40 
Open-Closed Principle 
OCP 11/11 – i.e. 
public class SportInfoParserDelegatingImpl implements SportInfoParser {// No changes required! 
private Map<String, SportInfoParser> parsers; 
public SportInfoParserDelegatingImpl (Map<String, SportInfoParser> parsers) { 
this.parsers = parsers; 
} 
public SportInfo parseSportInfo(String[] sportInfoArray) { 
SportInfoParser parser = parsers.get(sportInfoArray[0]); 
if (parser == null) { 
return null; 
} 
return parser.parseSportInfo(sportInfoArray); 
} 
} 
public class SportInfoParserMbaImpl implements SportInfoParser { ... } 
public class SportInfoParserNhlImpl implements SportInfoParser { ... } 
public class SportInfoParserMlbImpl implements SportInfoParser { ... } 
public class SportInfoParserWnbaImpl implements SportInfoParser { ... }
SINGLE RESPONSIBILITY PRINCIPLE
42 
Single Responsibility Principle 
SRP 1/8 - idea 
• Single class should have a single responsibility 
• Class should have only one reason to change 
• Friendly principles: 
– DRY – less responsibility – more descriptive class 
and method names, right location 
– OCP – less responsibility – less reason for 
modification
43 
Single Responsibility Principle 
SRP 2/8 – ex. 1 
public class CurrencyConverter { 
public BigDecimal convert(Currency from, Currency to, BigDecimal amount) { 
// 1. asks some online service to convert currency 
// 2. parses the answer and returns results 
} 
public BigDecimal getInflationIndex(Currency currency, Date from, Date to) { // 3 
// 4. ask some online service to get data about currency inflation 
// 5. parses the answer and returns results 
} 
} 
• 1, 2, 4, 5: What if online service changes? 
• 3: Why getInflationIndex located in 
CurrencyConverter?! 
• Principles violated: SRP, DRY
44 
Single Responsibility Principle 
SRP 3/8 – ex. 1 
public class CurrencyConverter { 
public BigDecimal convert(Currency from, Currency to, BigDecimal amount) { 
// asks some online service to convert currency 
// parses the answer and returns results 
} 
} 
public class InflationIndexCounter { 
public BigDecimal getInflationIndex(Currency currency, Date from, Date to) { 
// ask some online service to get data about currency inflation 
// parses the answer and returns results 
} 
} 
• Now each class have only single responsibility 
• Will change only CurrencyConverter if currency conversion logic 
changes 
• Methods placed at right location 
• Names are clear
45 
Single Responsibility Principle 
SRP 4/8 – ex. 2 
public class UserAuthenticator { 
public boolean authenticate(String username, String password) { 
User user = getUser(username); 
return user.getPassword().equals(password); 
} 
private User getUser(String username) { // 1 
// ... 
st.executeQuery("select user.name, user.password from user where id=?"); // 2 
// ... 
return user; 
} 
} 
• 1: Why getUser located in UserAuthenticator? 
• 2: What if jdbc will be changed to ORM or user 
might come from different sources? 
• Principles violation: SRP, DRY, OCP
46 
Single Responsibility Principle 
SRP 5/8 – ex. 2 
public class UserAuthenticator { 
private UserDetailsService userDetailsService; 
public UserAuthenticator(UserDetailsService service) { 
userDetailsService = service; 
} 
public boolean authenticate(String username, String password) { 
User user = userDetailsService.getUser(username); 
return user.getPassword().equals(password); 
} 
} 
• Now UserAuthenticator has single responsibility 
• UserAuthenticator doesn’t depend on specific 
UserDetailsService implementation
47 
Single Responsibility Principle 
SRP 6/8 – ex. 3 
public class DocumentServiceImpl { 
Document getCachedDocumentUuid(String documentUuid) { ... }; 
SignedDocument signDocument(Document document, Signature signature) { ... }; 
boolean isDocumentSignatureValid(SignedDocument signedDocument) { ... }; 
} 
• Task 1: need new implementation of 
DocumentService which uses ehcache as 
caching mechanism
48 
Single Responsibility Principle 
SRP 7/8 – ex. 3 
public class DocumentServiceEhCacheImpl extends DocumentServiceImpl { 
@Override 
public Document getCachedDocumentUuid(String documentUuid) { 
// some impl 
} 
} 
• Task 2: now we need new impl which the 
same as base but uses different way of 
verifying document signature
49 
Single Responsibility Principle 
SRP 8/8 – ex. 3 
public class DocumentServiceGost1024SignImpl extends DocumentServiceImpl { 
@Override 
public SignedDocument signDocument(Document document, Signature signature) { 
// some impl 
} 
@Override 
public boolean isDocumentSignatureValid(SignedDocument signedDocument) { 
// some impl 
} 
} 
• Task 3: ok, now we need impl which uses 
ehcache as caching mechanism and new 
signature verification mechanism
INTERFACE SEGREGATION 
PRINCIPLE
51 
Interface Segregation Principle 
ISP 1/4 - idea 
• Client code shouldn’t be obligated to depend on 
interfaces it doesn’t use 
• It’s better if class implements many small 
interfaces rather than one big/fat/polluted 
interface 
• Initially hard to distinguish with SRP, but there is a 
difference 
• Friendly principles 
– DRY – if ISP is violated, it might lead to code/logic 
duplicate
52 
Interface Segregation Principle 
ISP 2/4 – i.e. 
public interface SpamDetector { 
boolean isLooksLikeSpam(QuickMessage quickMessage); // 2 
} 
public interface QuickMessage { 
Author getAuthor(); 
String getMessageText(); 
} 
• 2: SpamDetector depends on QuickMessage 
interface, but there is no need to access 
author, why we need it here?! 
• Q: What will happen if you need to detect 
spam in file or, lets say, email?
53 
Interface Segregation Principle 
ISP 3/4 – i.e. 
public interface SpamDetector { 
boolean isLooksLikeSpam(QuickMessage quickMessage); 
} 
public interface QuickMessage { 
Author getAuthor(); 
String getMessageText(); 
} 
// ??? 
public interface TextFileContent { 
String getTextContent(); 
} 
// ??? 
public interface EmailMessage { // i.e. Legacy DTO you can’t change 
Author getAuthor(); 
String getSubject(); 
String getBody(); 
}
54 
Interface Segregation Principle 
ISP 4/4 – i.e. 
public interface SpamDetector { // It’s very generic now! 
boolean isLooksLikeSpam(HasText hasText); 
} 
public interface QuickMessage extends HasText { ... } 
public interface TextFileContent extends HasText { ... } 
public class LegacyEmailMessageHasTextAdapter implements HasText { 
public LegacyEmailMessageHasTextAdapter(EmailMessage emailMessage) { 
this.emailMessage = emailMessage; 
} 
@Override 
public String getText() { 
return emailMessage.getSubject() + emailMessage.getBody(); 
} 
}
DEPENDENCY INVERSION 
PRINCIPLE
56 
Dependency Inversion principle 
DI 1/4 - idea 
• Dependency Inversion 
– Code to abstraction, not to implementation 
– Objects that use other objects, shouldn’t create 
latter ones 
• Profits 
– Unit testing is possible 
– Easy change of concrete implementation 
– Each “module” depends on minimum and well-defined 
outer abstrations
57 
Dependency Inversion principle 
DI 2/4 – i.e. 
public interface HtmlParser { 
HtmlDocument parseUrl(String url); 
} 
public class DomBasedHtmlParser implements HtmlParser { 
public HtmlDocument parseUrl(String url) { 
// do the best 
} 
} 
public class Crawler { 
public void saveHtmlDocument() { 
DomBasedHtmlParser parser = new DomBasedHtmlParser(); 
HtmlDocument document = parser.parseUrl("http://....."); 
// do crawl 
} 
} 
• Unit testing of Crawler is not possible, you can’t mock parser 
• Crawler is not flexible, you can’t just use other implementattion
58 
Dependency Inversion principle 
DI 3/4 – i.e. 
public class Crawler { 
private DomBasedHtmlParser domBasedHtmlParser; 
public void Crawler(DomBasedHtmlParser domBasedHtmlParser) { 
this.domBasedHtmlParser = domBasedHtmlParser; 
} 
public void saveHtmlDocument() { 
HtmlDocument document = domBasedHtmlParser.parseUrl("http://....."); 
// do crawl 
} 
} 
• Ok, now we can inject it and do unit testing 
• But still locked on specific implementation
59 
Dependency Inversion principle 
DI 4/4 – i.e. 
public class Crawler { 
private HtmlParser htmlParser; 
public void Crawler(HtmlParser htmlParser) { 
this.htmlParser = htmlParser; 
} 
public void saveHtmlDocument() { 
HtmlDocument document = htmlParser.parseUrl("http://....."); 
// do crawl 
} 
} 
• Great! Now Crawler don’t depend on outer 
world specific and it’s not really interested in 
implementation details
LISKOV SUBSTITUTION PRINCIPLE
61 
Liskov Substitution Principle 
LSP 1/8 - idea 
• Liskov Substitution Principle 
– Says: derived types must be completely 
substitutable for their base types 
– Helps to use inheritance correctly 
– Helps to abstract from specific implementation 
• Friendly principles 
– DI 
– SRP, ISP
62 
Liskov Substitution Principle 
LSP 2/8 - idea 
• Major examples of LSP violation 
– Sub-class implements only some methods, other 
look redundant and … weird 
– Some methods behavior violates contract 
– equals() method symmetry requirement is 
violated 
– Subclass throws exception which are not declared 
by parent class/interface (java prevents from 
introducing checked exceptions)
63 
Liskov Substitution Principle 
LSP 3/8 – redundant methods 
class Bird extends Animal { 
@Override 
public void walk() { ... } 
@Override 
public void makeOffspring() { ... }; 
public void fly() {...} // will look weird for Emu 
} 
class Emu extends Bird { 
public void makeOffspring() {...} 
}
64 
Liskov Substitution Principle 
LSP 4/8 – redundant methods 
class Bird extends Animal { 
@Override 
public void walk() { ... } 
@Override 
public void makeOffspring() { ... }; 
} 
class FlyingBird extends Bird { 
public void fly() {...} 
} 
class Emu extends Bird { 
public void makeOffspring() {...} 
}
65 
Liskov Substitution Principle 
LSP 5/8 – contract violation 
interface ArraySorter { 
Object[] sort(Object[] args); 
} 
class DefaultArraySorter implements ArraySorter { 
public Object[] sort(Object[] array) { 
Object[] result = array.clone(); 
// ... 
} 
} 
class QuickArraySorter implements ArraySorter { 
public Object[] sort(Object[] array){ 
Object[] result = array; 
// original array changed! Error! Negative side-effect! 
} 
}
66 
Liskov Substitution Principle 
LSP 6/8 – buggy equals() 
public class Point { 
private int x; 
private int y; 
@Override 
public boolean equals(Object o) { 
if (this == o) return true; 
if (!(o instanceof Point)) return false; 
Point point = (Point) o; 
if (x != point.x) return false; 
if (y != point.y) return false; 
return true; 
} 
}
67 
Liskov Substitution Principle 
LSP 7/8 – buggy equals() 
public class ColoredPoint extends Point { 
private int color; 
@Override 
public boolean equals(Object o) { 
if (this == o) return true; 
if (!(o instanceof ColoredPoint)) return false; 
if (!super.equals(o)) return false; 
ColoredPoint that = (ColoredPoint) o; 
if (color != that.color) return false; 
return true; 
} 
} 
Point point = new Point(1, 1); 
ColoredPoint coloredPoint = new ColoredPoint(1, 1, 1); 
point.equals(coloredPoint)) == true 
coloredPoint.equals(point)) == false
68 
Liskov Substitution Principle 
LSP 8/8 – buggy equals() 
public class ColoredPoint { 
private Point point; // Use delegation instead of inheritance! 
private int color; 
} 
Point point = new Point(1, 1); 
ColoredPoint coloredPoint = new ColoredPoint(1, 1, 1); 
point.equals(coloredPoint) == false 
coloredPoint.equals(point) == false
THAT’S IT, THANK YOU!

Contenu connexe

Tendances

principles of object oriented class design
principles of object oriented class designprinciples of object oriented class design
principles of object oriented class designNeetu Mishra
 
Angular 2.0 forms
Angular 2.0 formsAngular 2.0 forms
Angular 2.0 formsEyal Vardi
 
Real Life Clean Architecture
Real Life Clean ArchitectureReal Life Clean Architecture
Real Life Clean ArchitectureMattia Battiston
 
Learning solid principles using c#
Learning solid principles using c#Learning solid principles using c#
Learning solid principles using c#Aditya Kumar Rajan
 
Single Responsibility Principle
Single Responsibility PrincipleSingle Responsibility Principle
Single Responsibility PrincipleEyal Golan
 
SOLID Design Principles applied in Java
SOLID Design Principles applied in JavaSOLID Design Principles applied in Java
SOLID Design Principles applied in JavaIonut Bilica
 
Clean code: SOLID (iOS)
Clean code: SOLID (iOS)Clean code: SOLID (iOS)
Clean code: SOLID (iOS)Maksym Husar
 
Spring I/O 2012: Natural Templating in Spring MVC with Thymeleaf
Spring I/O 2012: Natural Templating in Spring MVC with ThymeleafSpring I/O 2012: Natural Templating in Spring MVC with Thymeleaf
Spring I/O 2012: Natural Templating in Spring MVC with ThymeleafThymeleaf
 
SOLID Design Principles
SOLID Design PrinciplesSOLID Design Principles
SOLID Design PrinciplesSamuel Breed
 
Dependency injection presentation
Dependency injection presentationDependency injection presentation
Dependency injection presentationAhasanul Kalam Akib
 
Anatomy of a Spring Boot App with Clean Architecture - Spring I/O 2023
Anatomy of a Spring Boot App with Clean Architecture - Spring I/O 2023Anatomy of a Spring Boot App with Clean Architecture - Spring I/O 2023
Anatomy of a Spring Boot App with Clean Architecture - Spring I/O 2023Steve Pember
 

Tendances (20)

Clean code: SOLID
Clean code: SOLIDClean code: SOLID
Clean code: SOLID
 
principles of object oriented class design
principles of object oriented class designprinciples of object oriented class design
principles of object oriented class design
 
Angular 2.0 forms
Angular 2.0 formsAngular 2.0 forms
Angular 2.0 forms
 
Real Life Clean Architecture
Real Life Clean ArchitectureReal Life Clean Architecture
Real Life Clean Architecture
 
Learning solid principles using c#
Learning solid principles using c#Learning solid principles using c#
Learning solid principles using c#
 
Solid Principles
Solid PrinciplesSolid Principles
Solid Principles
 
Single Responsibility Principle
Single Responsibility PrincipleSingle Responsibility Principle
Single Responsibility Principle
 
SOLID Design Principles applied in Java
SOLID Design Principles applied in JavaSOLID Design Principles applied in Java
SOLID Design Principles applied in Java
 
Spring Boot
Spring BootSpring Boot
Spring Boot
 
Writing clean code
Writing clean codeWriting clean code
Writing clean code
 
Clean code: SOLID (iOS)
Clean code: SOLID (iOS)Clean code: SOLID (iOS)
Clean code: SOLID (iOS)
 
Spring I/O 2012: Natural Templating in Spring MVC with Thymeleaf
Spring I/O 2012: Natural Templating in Spring MVC with ThymeleafSpring I/O 2012: Natural Templating in Spring MVC with Thymeleaf
Spring I/O 2012: Natural Templating in Spring MVC with Thymeleaf
 
SOLID Design Principles
SOLID Design PrinciplesSOLID Design Principles
SOLID Design Principles
 
Clean code
Clean codeClean code
Clean code
 
Getting started with typescript
Getting started with typescriptGetting started with typescript
Getting started with typescript
 
Clean Code
Clean CodeClean Code
Clean Code
 
Dependency injection presentation
Dependency injection presentationDependency injection presentation
Dependency injection presentation
 
Anatomy of a Spring Boot App with Clean Architecture - Spring I/O 2023
Anatomy of a Spring Boot App with Clean Architecture - Spring I/O 2023Anatomy of a Spring Boot App with Clean Architecture - Spring I/O 2023
Anatomy of a Spring Boot App with Clean Architecture - Spring I/O 2023
 
Spring Security 5
Spring Security 5Spring Security 5
Spring Security 5
 
Micro Frontends
Micro FrontendsMicro Frontends
Micro Frontends
 

Similaire à SOLID, DRY, SLAP design principles

ActiveJDBC - ActiveRecord implementation in Java
ActiveJDBC - ActiveRecord implementation in JavaActiveJDBC - ActiveRecord implementation in Java
ActiveJDBC - ActiveRecord implementation in Javaipolevoy
 
Asynchronous single page applications without a line of HTML or Javascript, o...
Asynchronous single page applications without a line of HTML or Javascript, o...Asynchronous single page applications without a line of HTML or Javascript, o...
Asynchronous single page applications without a line of HTML or Javascript, o...Robert Schadek
 
Developer Tests - Things to Know (Vilnius JUG)
Developer Tests - Things to Know (Vilnius JUG)Developer Tests - Things to Know (Vilnius JUG)
Developer Tests - Things to Know (Vilnius JUG)vilniusjug
 
Intro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran MizrahiIntro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran MizrahiRan Mizrahi
 
Advance unittest
Advance unittestAdvance unittest
Advance unittestReza Arbabi
 
Finding bugs that matter with Findbugs
Finding bugs that matter with FindbugsFinding bugs that matter with Findbugs
Finding bugs that matter with FindbugsCarol McDonald
 
Top 10 RxJs Operators in Angular
Top 10 RxJs Operators in Angular Top 10 RxJs Operators in Angular
Top 10 RxJs Operators in Angular Jalpesh Vadgama
 
Object-oriented design principles
Object-oriented design principlesObject-oriented design principles
Object-oriented design principlesXiaoyan Chen
 
Back to the future with Java 7 (Geekout June/2011)
Back to the future with Java 7 (Geekout June/2011)Back to the future with Java 7 (Geekout June/2011)
Back to the future with Java 7 (Geekout June/2011)Martijn Verburg
 
55 new things in Java 7 - Devoxx France
55 new things in Java 7 - Devoxx France55 new things in Java 7 - Devoxx France
55 new things in Java 7 - Devoxx FranceDavid Delabassee
 

Similaire à SOLID, DRY, SLAP design principles (20)

ActiveJDBC - ActiveRecord implementation in Java
ActiveJDBC - ActiveRecord implementation in JavaActiveJDBC - ActiveRecord implementation in Java
ActiveJDBC - ActiveRecord implementation in Java
 
Asynchronous single page applications without a line of HTML or Javascript, o...
Asynchronous single page applications without a line of HTML or Javascript, o...Asynchronous single page applications without a line of HTML or Javascript, o...
Asynchronous single page applications without a line of HTML or Javascript, o...
 
Developer Tests - Things to Know (Vilnius JUG)
Developer Tests - Things to Know (Vilnius JUG)Developer Tests - Things to Know (Vilnius JUG)
Developer Tests - Things to Know (Vilnius JUG)
 
Intro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran MizrahiIntro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran Mizrahi
 
Java Tutorial
Java Tutorial Java Tutorial
Java Tutorial
 
Advance unittest
Advance unittestAdvance unittest
Advance unittest
 
SOLID Ruby, SOLID Rails
SOLID Ruby, SOLID RailsSOLID Ruby, SOLID Rails
SOLID Ruby, SOLID Rails
 
Stop that!
Stop that!Stop that!
Stop that!
 
Finding bugs that matter with Findbugs
Finding bugs that matter with FindbugsFinding bugs that matter with Findbugs
Finding bugs that matter with Findbugs
 
Top 10 RxJs Operators in Angular
Top 10 RxJs Operators in Angular Top 10 RxJs Operators in Angular
Top 10 RxJs Operators in Angular
 
Object-oriented design principles
Object-oriented design principlesObject-oriented design principles
Object-oriented design principles
 
SOLID Ruby SOLID Rails
SOLID Ruby SOLID RailsSOLID Ruby SOLID Rails
SOLID Ruby SOLID Rails
 
Clean Code 2
Clean Code 2Clean Code 2
Clean Code 2
 
Back to the future with Java 7 (Geekout June/2011)
Back to the future with Java 7 (Geekout June/2011)Back to the future with Java 7 (Geekout June/2011)
Back to the future with Java 7 (Geekout June/2011)
 
Java tutorial PPT
Java tutorial PPTJava tutorial PPT
Java tutorial PPT
 
Java tutorial PPT
Java tutorial  PPTJava tutorial  PPT
Java tutorial PPT
 
55 new things in Java 7 - Devoxx France
55 new things in Java 7 - Devoxx France55 new things in Java 7 - Devoxx France
55 new things in Java 7 - Devoxx France
 
SOLID Principles
SOLID PrinciplesSOLID Principles
SOLID Principles
 
Introduction to mysql part 3
Introduction to mysql part 3Introduction to mysql part 3
Introduction to mysql part 3
 
What's in a name
What's in a nameWhat's in a name
What's in a name
 

Dernier

08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessPixlogix Infotech
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 

Dernier (20)

08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 

SOLID, DRY, SLAP design principles

  • 1. Design principles presenter: Sergey Karpushin
  • 2. 2 Agenda • Justification • DRY • SLAP • Single Responsibility • Open/Closed • Liskov substitution • Interface segregation • Dependency inversion
  • 3. 3 Justification 1/4 Where you spend time? Fixing tons of bugs Implementing new functionality How do you feel about new change requests? It’s ok, just need to make right design decision I’m scared! This will break something How complicated current codebase is? It’s large, but easy to understand and safe to change I need to expand consciousness to have a clue
  • 4. 4 Justification 2/4 Where you spend time? Fixing tons of bugs Implementing new functionality How do you feel about new change requests? It’s ok, just need to make right design decision I’m scared! This will break something How complicated current codebase is? It’s large, but easy to understand and safe to change I need to expand consciousness to have a clue Signal words: urgent, stress, overtime, chaos, more than 100 open bugs, “who wrote this crap?”
  • 5. 5 Justification 3/4 Where you spend time? Fixing tons of bugs Implementing new functionality How do you feel about new change requests? It’s ok, just need to make right design decision I’m scared! This will break something How complicated current codebase is? It’s large, but easy to understand and safe to change I need to expand consciousness to have a clue Signal words: ahead of schedule, only 3 open bugs, thank you
  • 6. 6 Justification 4/4 OOD & other related principles • Takes time to understand and feel for the first time • Relatively easy to apply later
  • 8. 8 Naming convention • Design principles are common for all Object-Oriented languages • Java naming conventions used within this presentation • Name example for interfaces, DTOs and “simple” classes: UserService • Name example for classes which implements interfaces UserServiceImpl • All variable and parameter names example camelCaseName
  • 10. 10 DRY 1/15 Don’t Repeat Yourself • Do not Repeat Yourself – Reuse your code, do not duplicate it – Assign clear names – Choose right location • Clear names and right location allows to identify duplicate candidates
  • 11. 11 Don’t Repeat Yourself DRY 2/15 – reuse • Maintain “single source of truth” – Change once – Test once • Do not confuse with abstractions, it’s different
  • 12. 12 Don’t Repeat Yourself DRY 3/15 – reuse • Same code in multiple places stmt.execute("SELECT name, email FROM users WHERE id = ?", id);
  • 13. 13 Don’t Repeat Yourself DRY 4/15 – reuse • A change required? i.e. database field renamed stmt.execute("SELECT name, email FROM users WHERE id = ?", id);
  • 14. 14 Don’t Repeat Yourself DRY 5/15 – reuse • A multiple changes required! stmt.execute("SELECT last_name, email FROM users WHERE id = ?", id);
  • 15. 15 DRY 6/15 – reuse • What if code is in one place? getUserById(id); stmt.execute( "SELECT name, email FROM users WHERE id = ?", id); Don’t Repeat Yourself
  • 16. 16 DRY 7/15 – reuse • Exactly! 1 change required. getUserById(id); stmt.execute( "SELECT last_name, email FROM users WHERE id = ?", id); Don’t Repeat Yourself
  • 17. 17 DRY 8/15 – confusing w/ abstractions • Suppose we have Users and Articles getUserNameById(id); stmt.execute( "SELECT name FROM users WHERE id = ?", id); getArticleNameById(id); stmt.execute( "SELECT name FROM articles WHERE id = ?", id); Don’t Repeat Yourself
  • 18. 18 DRY 9/15 – confusing w/ abstractions • Hey! It was a duplicate! We got rid of it! getObjectNameById(table, id); stmt.execute( "SELECT name FROM ? WHERE id = ?", table, id); Don’t Repeat Yourself
  • 19. Don’t Repeat Yourself DRY 10/15 – confusing w/ abstractions 19 • Incoming change request: “Article name must be displayed along with author and date”
  • 20. Don’t Repeat Yourself DRY 11/15 – confusing w/ abstractions 20 • Complete mess, this is what you end up with ?!?!?!? getObjectNameById(table, id); stmt.execute( ?!?!?!? "SELECT name FROM ? WHERE id = ?", id); ?!?!?!? ?!?!?!? ?!?!?!?
  • 21. Don’t Repeat Yourself DRY 12/15 – confusing w/ abstractions 21 • For abstractions recommended approach is – Write – Copy & Paste – Only then – extract abstraction
  • 22. 22 Don’t Repeat Yourself DRY 13/15 – clear names • Q: How can I determine if name is “clear”? • A: If javadoc will look redundant • Q: How to pick clear name? • A: Write java doc, get essence of it, use as name • Q: It sometimes so complicated to pick short but still clear name! • A: Be honest with yourself, it happens rarely. In such case write descriptive javadoc
  • 23. 23 Don’t Repeat Yourself DRY 14/15 – clear names An example • You can say almost nothing about it: String[] l1 = getArr(str1); • But this one is pretty descriptive: String[] fieldValues = parseCsvRow(csvRow);
  • 24. 24 Don’t Repeat Yourself DRY 15/15 – right location • No one will guess that it might be here! package ru.it.projects.umms.dom.users; public class ArrayUtils { }
  • 25. SINGLE LAYER OF ABSTRACTION PRINCIPLE
  • 26. 26 Single Layer of Abstraction Principle SLAP 1/3 • Single Layer of Abstraction Principle …for methods • Have common things with DRY, SRP, ISP • Basic idea is: – Do not write endless methods which logic is hard to follow. – All instructions for each method should operate on same level of abstraction and related to “one task”
  • 27. 27 Single Layer of Abstraction Principle SLAP 2/3 (violated) private UserInfo retrieveUserInfo(String userToken) { String userTokenParts[] = userToken.split(":"); long userId; if (userTokenParts.length == 1) { userId = Long.parseLong(userToken); } else { if ("legacy".equals(userTokenParts[0])) { userId = Long.parseLong(userTokenParts[1]); } else { userId = Long.parseLong(userTokenParts[0] + userTokenParts[1]); } } String url = userServiceBasePath; if ("legacy".equals(userTokenParts[0])) { url += "/v1/getUserData?userId=" + userId; } else { url += "/v2/users/" + userId; } try { HttpResponse getResponse = client.execute(url); final int statusCode = getResponse.getStatusLine().getStatusCode(); if (statusCode != HttpStatus.SC_OK) { Log.w(getClass().getSimpleName(), "Error " + statusCode + " for URL " + url); return null; }
  • 28. 28 Single Layer of Abstraction Principle SLAP 3/3 (following) private UserInfo retrieveUserInfo(String userToken) { long userId = extractUserIdFromToken(userToken); if (isLegacyUser(userToken)) { return retreiveLegacyUserInfo(userId); } else { return retreiveUserInfo(userId, extractUserDomainIdFromToken(userToken)); } } • The only concern: you’ll have more methods. Yes, but each of them is clear and damn simple to follow (thus maintain)
  • 30. 30 Open-Closed Principle OCP 1/11 – general idea Open-Closed Principle • Class should be – Open for extension – Closed for modification • Effects – Increased stability – existing code (almost) never changes – Increased modularity, but many small classes
  • 31. 31 Open-Closed Principle OCP 2/11 – i.e. • Customer brings new user story: As the user I want to see results of past games. Let’s keep up with NHL & NBA games
  • 32. 32 Open-Closed Principle OCP 3/11 – i.e. public class SportInfoParser { public SportInfo parseSportInfo(String[] sportInfoArray) { if ("nba".equals(sportInfoArray[0])) { NbaSportInfo nbaSportInfo = new NbaSportInfo(); Map<Long, Integer> scores = new HashMap<Long, Integer>(); scores.put(Long.parseLong(sportInfoArray[12]), Integer.parseInt(sportInfoArray[13])); NbaSportInfo.setScores(scores); return nbaSportInfo; } else if ("nhl".equals(sportInfoArray[0])) { NhlSportInfo nhlSportInfo = new NhlSportInfo(); nhlSportInfo.setSlapShotCount(1); return nhlSportInfo; } } }
  • 33. 33 Open-Closed Principle OCP 4/11 – i.e. • Customer feedback: Thank you, it works well! • And brings another user story: As the user I want to see results of MLB games
  • 34. 34 Open-Closed Principle OCP 5/11 – i.e. public class SportInfoParser { public SportInfo parseSportInfo(String[] sportInfoArray) { if ("nba".equals(sportInfoArray[0])) { NbaSportInfo nbaSportInfo = new NbaSportInfo(); Map<Long, Integer> scores = new HashMap<Long, Integer>(); scores.put(Long.parseLong(sportInfoArray[12]), Integer.parseInt(sportInfoArray[13])); NbaSportInfo.setScores(scores); return nbaSportInfo; } else if ("nhl".equals(sportInfoArray[0])) { NhlSportInfo nhlSportInfo = new NhlSportInfo(); nhlSportInfo.setSlapShotCount(1); return nhlSportInfo; } else if (sportInfoArray[0].equalsIgnoreCase("mlb")) { MlbSportInfo mlbSportInfo = new MlbSportInfo(); mlbSportInfo.setHits(Integer.parseInt(sportInfoArray[1])); mlbSportInfo.setRuns(Integer.parseInt(sportInfoArray[2])); return mlbSportInfo; } } }
  • 35. 35 Open-Closed Principle OCP 6/11 – i.e. • Customer feedback: Why users see errors? I pay you for working app, not for errors! Make it work right till evening! • After debugging you found silly NPE mistake
  • 36. 36 Open-Closed Principle OCP 7/11 – i.e. public class SportInfoParser { public SportInfo parseSportInfo(String[] sportInfoArray) { if ("nba".equals(sportInfoArray[0])) { NbaSportInfo nbaSportInfo = new NbaSportInfo(); Map<Long, Integer> scores = new HashMap<Long, Integer>(); scores.put(Long.parseLong(sportInfoArray[12]), Integer.parseInt(sportInfoArray[13])); NbaSportInfo.setScores(scores); return nbaSportInfo; } else if ("nhl".equals(sportInfoArray[0])) { NhlSportInfo nhlSportInfo = new NhlSportInfo(); nhlSportInfo.setSlapShotCount(1); return nhlSportInfo; } else if (sportInfoArray[0].equalsIgnoreCase("mlb")) { // NPE occured MlbSportInfo mlbSportInfo = new MlbSportInfo(); mlbSportInfo.setHits(Integer.parseInt(sportInfoArray[1])); mlbSportInfo.setRuns(Integer.parseInt(sportInfoArray[2])); return mlbSportInfo; } } }
  • 37. 37 Open-Closed Principle OCP 8/11 – i.e. • You did small change, but whole class became unstable • OCP is violated - we modified existing code • How to make code open for extension? – Use inheritance – Use delegation/composition
  • 38. 38 Open-Closed Principle OCP 9/11 – i.e. public class SportInfoParserDelegatingImpl implements SportInfoParser { private Map<String, SportInfoParser> parsers; public SportInfoParserDelegatingImpl (Map<String, SportInfoParser> parsers) { this.parsers = parsers; } public SportInfo parseSportInfo(String[] sportInfoArray) { SportInfoParser parser = parsers.get(sportInfoArray[0]); if (parser == null) { return null; } return parser.parseSportInfo(sportInfoArray); } } public class SportInfoParserMbaImpl implements SportInfoParser { ... } public class SportInfoParserNhlImpl implements SportInfoParser { ... } public class SportInfoParserMlbImpl implements SportInfoParser { ... }
  • 39. 39 Open-Closed Principle OCP 10/11 – i.e. • You fixed bug and did refactoring to follow OCP • Customer feedback: Great, now it works well! Lets add support for WNBA!
  • 40. 40 Open-Closed Principle OCP 11/11 – i.e. public class SportInfoParserDelegatingImpl implements SportInfoParser {// No changes required! private Map<String, SportInfoParser> parsers; public SportInfoParserDelegatingImpl (Map<String, SportInfoParser> parsers) { this.parsers = parsers; } public SportInfo parseSportInfo(String[] sportInfoArray) { SportInfoParser parser = parsers.get(sportInfoArray[0]); if (parser == null) { return null; } return parser.parseSportInfo(sportInfoArray); } } public class SportInfoParserMbaImpl implements SportInfoParser { ... } public class SportInfoParserNhlImpl implements SportInfoParser { ... } public class SportInfoParserMlbImpl implements SportInfoParser { ... } public class SportInfoParserWnbaImpl implements SportInfoParser { ... }
  • 42. 42 Single Responsibility Principle SRP 1/8 - idea • Single class should have a single responsibility • Class should have only one reason to change • Friendly principles: – DRY – less responsibility – more descriptive class and method names, right location – OCP – less responsibility – less reason for modification
  • 43. 43 Single Responsibility Principle SRP 2/8 – ex. 1 public class CurrencyConverter { public BigDecimal convert(Currency from, Currency to, BigDecimal amount) { // 1. asks some online service to convert currency // 2. parses the answer and returns results } public BigDecimal getInflationIndex(Currency currency, Date from, Date to) { // 3 // 4. ask some online service to get data about currency inflation // 5. parses the answer and returns results } } • 1, 2, 4, 5: What if online service changes? • 3: Why getInflationIndex located in CurrencyConverter?! • Principles violated: SRP, DRY
  • 44. 44 Single Responsibility Principle SRP 3/8 – ex. 1 public class CurrencyConverter { public BigDecimal convert(Currency from, Currency to, BigDecimal amount) { // asks some online service to convert currency // parses the answer and returns results } } public class InflationIndexCounter { public BigDecimal getInflationIndex(Currency currency, Date from, Date to) { // ask some online service to get data about currency inflation // parses the answer and returns results } } • Now each class have only single responsibility • Will change only CurrencyConverter if currency conversion logic changes • Methods placed at right location • Names are clear
  • 45. 45 Single Responsibility Principle SRP 4/8 – ex. 2 public class UserAuthenticator { public boolean authenticate(String username, String password) { User user = getUser(username); return user.getPassword().equals(password); } private User getUser(String username) { // 1 // ... st.executeQuery("select user.name, user.password from user where id=?"); // 2 // ... return user; } } • 1: Why getUser located in UserAuthenticator? • 2: What if jdbc will be changed to ORM or user might come from different sources? • Principles violation: SRP, DRY, OCP
  • 46. 46 Single Responsibility Principle SRP 5/8 – ex. 2 public class UserAuthenticator { private UserDetailsService userDetailsService; public UserAuthenticator(UserDetailsService service) { userDetailsService = service; } public boolean authenticate(String username, String password) { User user = userDetailsService.getUser(username); return user.getPassword().equals(password); } } • Now UserAuthenticator has single responsibility • UserAuthenticator doesn’t depend on specific UserDetailsService implementation
  • 47. 47 Single Responsibility Principle SRP 6/8 – ex. 3 public class DocumentServiceImpl { Document getCachedDocumentUuid(String documentUuid) { ... }; SignedDocument signDocument(Document document, Signature signature) { ... }; boolean isDocumentSignatureValid(SignedDocument signedDocument) { ... }; } • Task 1: need new implementation of DocumentService which uses ehcache as caching mechanism
  • 48. 48 Single Responsibility Principle SRP 7/8 – ex. 3 public class DocumentServiceEhCacheImpl extends DocumentServiceImpl { @Override public Document getCachedDocumentUuid(String documentUuid) { // some impl } } • Task 2: now we need new impl which the same as base but uses different way of verifying document signature
  • 49. 49 Single Responsibility Principle SRP 8/8 – ex. 3 public class DocumentServiceGost1024SignImpl extends DocumentServiceImpl { @Override public SignedDocument signDocument(Document document, Signature signature) { // some impl } @Override public boolean isDocumentSignatureValid(SignedDocument signedDocument) { // some impl } } • Task 3: ok, now we need impl which uses ehcache as caching mechanism and new signature verification mechanism
  • 51. 51 Interface Segregation Principle ISP 1/4 - idea • Client code shouldn’t be obligated to depend on interfaces it doesn’t use • It’s better if class implements many small interfaces rather than one big/fat/polluted interface • Initially hard to distinguish with SRP, but there is a difference • Friendly principles – DRY – if ISP is violated, it might lead to code/logic duplicate
  • 52. 52 Interface Segregation Principle ISP 2/4 – i.e. public interface SpamDetector { boolean isLooksLikeSpam(QuickMessage quickMessage); // 2 } public interface QuickMessage { Author getAuthor(); String getMessageText(); } • 2: SpamDetector depends on QuickMessage interface, but there is no need to access author, why we need it here?! • Q: What will happen if you need to detect spam in file or, lets say, email?
  • 53. 53 Interface Segregation Principle ISP 3/4 – i.e. public interface SpamDetector { boolean isLooksLikeSpam(QuickMessage quickMessage); } public interface QuickMessage { Author getAuthor(); String getMessageText(); } // ??? public interface TextFileContent { String getTextContent(); } // ??? public interface EmailMessage { // i.e. Legacy DTO you can’t change Author getAuthor(); String getSubject(); String getBody(); }
  • 54. 54 Interface Segregation Principle ISP 4/4 – i.e. public interface SpamDetector { // It’s very generic now! boolean isLooksLikeSpam(HasText hasText); } public interface QuickMessage extends HasText { ... } public interface TextFileContent extends HasText { ... } public class LegacyEmailMessageHasTextAdapter implements HasText { public LegacyEmailMessageHasTextAdapter(EmailMessage emailMessage) { this.emailMessage = emailMessage; } @Override public String getText() { return emailMessage.getSubject() + emailMessage.getBody(); } }
  • 56. 56 Dependency Inversion principle DI 1/4 - idea • Dependency Inversion – Code to abstraction, not to implementation – Objects that use other objects, shouldn’t create latter ones • Profits – Unit testing is possible – Easy change of concrete implementation – Each “module” depends on minimum and well-defined outer abstrations
  • 57. 57 Dependency Inversion principle DI 2/4 – i.e. public interface HtmlParser { HtmlDocument parseUrl(String url); } public class DomBasedHtmlParser implements HtmlParser { public HtmlDocument parseUrl(String url) { // do the best } } public class Crawler { public void saveHtmlDocument() { DomBasedHtmlParser parser = new DomBasedHtmlParser(); HtmlDocument document = parser.parseUrl("http://....."); // do crawl } } • Unit testing of Crawler is not possible, you can’t mock parser • Crawler is not flexible, you can’t just use other implementattion
  • 58. 58 Dependency Inversion principle DI 3/4 – i.e. public class Crawler { private DomBasedHtmlParser domBasedHtmlParser; public void Crawler(DomBasedHtmlParser domBasedHtmlParser) { this.domBasedHtmlParser = domBasedHtmlParser; } public void saveHtmlDocument() { HtmlDocument document = domBasedHtmlParser.parseUrl("http://....."); // do crawl } } • Ok, now we can inject it and do unit testing • But still locked on specific implementation
  • 59. 59 Dependency Inversion principle DI 4/4 – i.e. public class Crawler { private HtmlParser htmlParser; public void Crawler(HtmlParser htmlParser) { this.htmlParser = htmlParser; } public void saveHtmlDocument() { HtmlDocument document = htmlParser.parseUrl("http://....."); // do crawl } } • Great! Now Crawler don’t depend on outer world specific and it’s not really interested in implementation details
  • 61. 61 Liskov Substitution Principle LSP 1/8 - idea • Liskov Substitution Principle – Says: derived types must be completely substitutable for their base types – Helps to use inheritance correctly – Helps to abstract from specific implementation • Friendly principles – DI – SRP, ISP
  • 62. 62 Liskov Substitution Principle LSP 2/8 - idea • Major examples of LSP violation – Sub-class implements only some methods, other look redundant and … weird – Some methods behavior violates contract – equals() method symmetry requirement is violated – Subclass throws exception which are not declared by parent class/interface (java prevents from introducing checked exceptions)
  • 63. 63 Liskov Substitution Principle LSP 3/8 – redundant methods class Bird extends Animal { @Override public void walk() { ... } @Override public void makeOffspring() { ... }; public void fly() {...} // will look weird for Emu } class Emu extends Bird { public void makeOffspring() {...} }
  • 64. 64 Liskov Substitution Principle LSP 4/8 – redundant methods class Bird extends Animal { @Override public void walk() { ... } @Override public void makeOffspring() { ... }; } class FlyingBird extends Bird { public void fly() {...} } class Emu extends Bird { public void makeOffspring() {...} }
  • 65. 65 Liskov Substitution Principle LSP 5/8 – contract violation interface ArraySorter { Object[] sort(Object[] args); } class DefaultArraySorter implements ArraySorter { public Object[] sort(Object[] array) { Object[] result = array.clone(); // ... } } class QuickArraySorter implements ArraySorter { public Object[] sort(Object[] array){ Object[] result = array; // original array changed! Error! Negative side-effect! } }
  • 66. 66 Liskov Substitution Principle LSP 6/8 – buggy equals() public class Point { private int x; private int y; @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Point)) return false; Point point = (Point) o; if (x != point.x) return false; if (y != point.y) return false; return true; } }
  • 67. 67 Liskov Substitution Principle LSP 7/8 – buggy equals() public class ColoredPoint extends Point { private int color; @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof ColoredPoint)) return false; if (!super.equals(o)) return false; ColoredPoint that = (ColoredPoint) o; if (color != that.color) return false; return true; } } Point point = new Point(1, 1); ColoredPoint coloredPoint = new ColoredPoint(1, 1, 1); point.equals(coloredPoint)) == true coloredPoint.equals(point)) == false
  • 68. 68 Liskov Substitution Principle LSP 8/8 – buggy equals() public class ColoredPoint { private Point point; // Use delegation instead of inheritance! private int color; } Point point = new Point(1, 1); ColoredPoint coloredPoint = new ColoredPoint(1, 1, 1); point.equals(coloredPoint) == false coloredPoint.equals(point) == false