Clean Systems - GitHub Pages · Dependency Injection • Special type of Inversion of Control. •...

Preview:

Citation preview

Clean SystemsClean Code at the Architecture Level

Dean Wamplerdean@objectmentor.comIM’s, Twitter: deanwampler

1Wednesday, August 6, 2008

2Wednesday, August 6, 2008

How would you build a city?

3Wednesday, August 6, 2008

4Wednesday, August 6, 2008

5Wednesday, August 6, 2008

Cities are modular

• They have appropriate levels of abstraction.

• They separate concerns.

6Wednesday, August 6, 2008

Your software systems?

• Appropriate abstractions?

• Clear separation of concerns?

7Wednesday, August 6, 2008

Clean systems are built on clean code

Leave now if code makes you squeamish...

8Wednesday, August 6, 2008

Separate construction

fromuse

#1

9Wednesday, August 6, 2008

During construction

• People in hard hats.

• Lots of heavy lifting.

• ...

10Wednesday, August 6, 2008

During use

• People in nicer clothes.

• Business tasks.

• ...

11Wednesday, August 6, 2008

Software construction vs. use

• Startup is one task.

• Component wiring.

• Running involves different tasks.

12Wednesday, August 6, 2008

public Service getService() { if (service == null) // Good enough default for most cases? service = new MyServiceImpl(...); return service; }

An example

Lazy Initialization Pattern

13Wednesday, August 6, 2008

public Service getService() { if (service == null) // Good enough default for most cases? service = new MyServiceImpl(...); return service; }

What’s Wrong with LI?“Wiring strategy” scattered and tangled.

Specific decisions hard coded.

14Wednesday, August 6, 2008

Other problems...

• Testing

• Must somehow set a mock for service before getService called.

• Must still compile with MyServiceImpl.

• Is MyServiceImpl really the best default?

• Breaks the Single Responsibility Principle

15Wednesday, August 6, 2008

Setup concern

• Requires a global strategy.

• Consistent approach.

• Modularized decisions.

16Wednesday, August 6, 2008

SolutionDependency Injection

17Wednesday, August 6, 2008

Dependency Injection

• Special type of Inversion of Control.

• Objects are given their dependencies

• Passive vs. Active

• Authoritative mechanism makes wiring decisions.

18Wednesday, August 6, 2008

Options

• Attribute “setters”.

• Constructor arguments.

• Object leaves constructor fully formed.

• Slightly better.

19Wednesday, August 6, 2008

Spring Framework<beans> <bean id="service" class="org.example.services.MyServiceImpl"/>

<bean id="clientOfService" class="org.example.app.ClientImpl" p:service-name= "service"/> ...</beans>

XmlBeanFactory bf = new XmlBeanFactory( new ClassPathResource("app.xml", getClass()));Client client = (Client) bf.getBean("client");

20Wednesday, August 6, 2008

Dependency Injection

• Separates construction from use.

• Decouples abstractions from implementations.

21Wednesday, August 6, 2008

Scale up systems

on demand

#2

22Wednesday, August 6, 2008

Small vs. Large Systems

23Wednesday, August 6, 2008

Common Myth:

Why didn’t you get the design

right the first time?

24Wednesday, August 6, 2008

Design Dilemma

• The perfect design for today’s system.

vs.

• The perfect design for tomorrow’s system.

25Wednesday, August 6, 2008

Agile methods

• Taught us to evolve the design to meet today’s needs,

• But keep it adaptable for tomorrow’s needs

• Without anticipatory design.

26Wednesday, August 6, 2008

Software is unique

• Unlike physical structures,

• We can change everything in software, even the architecture.

27Wednesday, August 6, 2008

Software is unique

• … but only if we keep it agile!

28Wednesday, August 6, 2008

How not to keep it agileEJB’s versions 1 and 2

29Wednesday, August 6, 2008

Enterprise Java Beans

• Forced tangling of concerns:

• Application logic mixed with

• Container life-cycle, etc.

• Persistence,

• etc.

30Wednesday, August 6, 2008

public interface BankLocal extends javax.ejb.EJBLocalObject { …

Example: Bank EJB

• Forced to subclass an EJB class.

• Can’t use application domain hierarchy.

• Tight coupling to container details.

31Wednesday, August 6, 2008

… String getCity() throws java.ejb.EJBException; void addAccount(AccountDTO dto) throws java.ejb.EJBException; …

Example: Bank EJB

• Tight coupling for methods, too.

32Wednesday, August 6, 2008

public abstract class Bank implements javax.ejb.EntityBean { …

EJB implementation

• Forced to implement EJB interface

33Wednesday, August 6, 2008

EJB implementation … public void addAccount(AccountDTO dto) { InitialContext ctx = new InitialContext(); AccountHomeLocal accountHome = ctx.lookup("AccountHomeLocal"); AccountLocal account = accountHome.create(dto); Collection accounts = getAccounts(); accounts.add(account); }

34Wednesday, August 6, 2008

EJB Implementation

… // Required container methods... public void ejbActivate() {} public void ejbPassivate() {} public void ejbLoad() {} public void ejbStore() {} public void ejbRemove() {} …

35Wednesday, August 6, 2008

But wait, there’s more!

• Several more classes and interfaces.

• Many more methods.

• XML to define

• Transactions,

• Persistence mapping,

• Security, ...

36Wednesday, August 6, 2008

Forget about:

• Reuse.

• Object orientation of your domain model.

• => Lot’s of duplication between EJB’s and POJO domain objects.

• Easy TDD.

• High productivity...

37Wednesday, August 6, 2008

But, not all was wrong

• Using XML to specify transactional, persistence, and security behaviors,

• Separated these concerns from code.

• EJBs anticipated Aspect-Oriented Programming.

38Wednesday, August 6, 2008

SolutionAspect-Oriented Programming

39Wednesday, August 6, 2008

public class BankAccount { private Money balance; public Money getBalance () {…} public void credit(Money amount) { balance += amount; } public void debit(Money amount) { balance -= amount; } …}

Clean Code

40Wednesday, August 6, 2008

However,

real applications need:

Transactions

Persistence

Security

public void credit(…) { … } public void debit(…) { … }

41Wednesday, August 6, 2008

public void credit(Money amount) throws ApplicationException { try { Money oldBalance = balance; beginTransaction(); balance += amount; persistChange(this); …

So credit becomes…

42Wednesday, August 6, 2008

catch (Throwable th) { logError(th); balance = oldBalance; throw new ApplicationException(th); } finally { endTransaction(); }}

43Wednesday, August 6, 2008

We’re mixing multiple domains, with fine-grained intersections.

Transactions

Persistence

Security

“Problem Domain”

“tangled” code

“scattered” logic44Wednesday, August 6, 2008

Objects alone don’t prevent tangling.

45Wednesday, August 6, 2008

Aspects restore modularity by encapsulating the intersections.

Transactions

Persistence

Security

TransactionAspect

PersistenceAspect

SecurityAspect

46Wednesday, August 6, 2008

AOP tool options

• AspectJ

• “Pure Java” Spring AOP or JBoss AOP

47Wednesday, August 6, 2008

public aspect PersistentBankAccount { pointcut stateChange(BankAccount ba): (call(* BankAccount.debit(..)) || call(* BankAccount.credit(..))) && this(ba);

after(BankAccount ba): stateChange(ba) { persistChange(ba); }}

AspectJ

48Wednesday, August 6, 2008

public aspect PersistentBankAccount { pointcut stateChange(BankAccount ba): (call(* BankAccount.debit(..)) || call(* BankAccount.credit(..))) && this(ba);

after(BankAccount ba): stateChange(ba) { persistChange(ba); }}

AspectJ“Class-like” construct

When state changes occur.

When and how to persist changes.

49Wednesday, August 6, 2008

Spring AOP<beans> <bean id="bankDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://localhost:3306/mydb" p:username="me" />

<bean id="bankDataAccessObject" class="com.banking.persistence.BankDataAccessObject" p:dataSource-ref= "bankDataSource"/>

<bean id="bank" class="com.banking.model.Bank" p:dataAccessObject-ref= "bankDataAccessObject"/></beans>

50Wednesday, August 6, 2008

: appDataSource

: bankDataAccessObject

: bank

getAccounts(): client

“Matryoshka” doll*

* i.e., Russian nested doll51Wednesday, August 6, 2008

EJB version 3

• Largely adopted the POJO model of Spring AOP.

52Wednesday, August 6, 2008

Aspect-Oriented Programming

• Separates concerns with fine-grained coupling.

• Allows concerns to evolve and scale independently.

• Allows architectures to evolve and scale.

53Wednesday, August 6, 2008

Test drivethe

system architecture

#3

54Wednesday, August 6, 2008

Cities are modular

• Discrete components.

• Minimal coupling.

• Concurrent modifications.

• Concurrent execution.

55Wednesday, August 6, 2008

They grow from villages

• Dirt roads are replaced by paved roads.

• Highways are added.

• Small buildings are replaced with towers.

The transition can be painful at times.

56Wednesday, August 6, 2008

Big Design Up Front?

• Architecture evolution is possible if,

• The components that implement concerns are decoupled from one another and

• The components are wired together using aspect-like mechanisms.

57Wednesday, August 6, 2008

Hazards of BDUF

• You’re thinking in a vacuum, without feedback from a running system.

• It’s hard to throw the design away when you’ve invested so much into it.

58Wednesday, August 6, 2008

SolutionTest-Driven Development

59Wednesday, August 6, 2008

In TDD, tests are proxies for

requirements

60Wednesday, August 6, 2008

Therefore, grow the system in response to

“test pressure”

61Wednesday, August 6, 2008

Optimizedecision making

#4

62Wednesday, August 6, 2008

The best decisions:

• are made at the last responsible moment,

• when you have the most recent information.

63Wednesday, August 6, 2008

SolutionIncremental Evolution

64Wednesday, August 6, 2008

With a test-drivenarchitecture,

you can optimize decision making

65Wednesday, August 6, 2008

Timing decisions

• You can make

• many small decisions,

• rather than big, risky decisions.

66Wednesday, August 6, 2008

This is only possible with an agile architecture

67Wednesday, August 6, 2008

Use standardswisely,

when they add demonstrable value

#5

68Wednesday, August 6, 2008

Benefits of Standards

• Reuse and encapsulation of

• ideas.

• components.

• Shared expertise.

69Wednesday, August 6, 2008

Drawbacks of Standards

• Slow to emerge.

• Design by committee.

• Bloat.

70Wednesday, August 6, 2008

Does the standardmeet the needs it was

intended to serve?

71Wednesday, August 6, 2008

Minimize themental gap between

requirements and code

#6

72Wednesday, August 6, 2008

Does your coderead like the

problem domain?

73Wednesday, August 6, 2008

SolutionDomain-Specific Languages

74Wednesday, August 6, 2008

Every Domain has a Language

• Rich vocabulary.

• Idioms and patterns.

• Clear and concise communications.

75Wednesday, August 6, 2008

Code should read like the domain

• DSL’s

• Introduce appropriate levels of abstraction.

• Minimize mental gap between domain concepts and code.

• Optimize communication.

76Wednesday, August 6, 2008

Recap

• Separate construction from use.

• Use dependency injection.

• Scale up on demand.

• Decouple concerns with Aspects.

77Wednesday, August 6, 2008

Recap

• Test-drive the system architecture.

• Requires modular concerns.

• Optimize decision making.

• An agile architecture lets you make decisions at the most appropriate times.

78Wednesday, August 6, 2008

Recap

• Use standards wisely.

• Only if they demonstrate value.

• Use domain-specific languages.

• Map the domain to code.

• Introduce appropriate levels of abstraction.

79Wednesday, August 6, 2008

Final Thought:

Complexity kills. It sucks the life out of developers, it makes products difficult to plan, build and test. ...

Each of us should ... explore and embrace techniques to reduce complexity.

Ray Ozzie, Chief Technology Officer, Microsoft Corporation

80Wednesday, August 6, 2008

Thank You!

• dean@objectmentor.com

• http://blog.objectmentor.com

• http://aspectprogramming.com/papers

81Wednesday, August 6, 2008

Recommended