Whoops! Where did my architecture go?

Preview:

DESCRIPTION

Slides of my SpringOne 2011 talk on how to implement and enforce architecture in codebases.

Citation preview

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Whoops! Where did my architecture go?Approaches to architecture management for Java and Spring applications

Oliver Gierke

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Oliver Gierke

Spring DataCore/JPA/MongoDB

ogierke@vmware.comwww.olivergierke.deolivergierke

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

BackgroundFew years of consulting

Lots of code reviewsEoin Woods‘ talk on InfoQ

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

RoadmapArchitecture 101

A Java packages modelHera

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Architecture 101

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Know your dependencies

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

GranularityModulesLayers

Vertical slicesSubsystems

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

GranularityJava ARchive

PackageClass

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Of layersand slices…

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Layer 1

Layer 2

Layer 3

Slice A Slice B Slice C

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

LayersWell understood

Known to developersLess important to business

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

SlicesHardly understoodNew to developers

Key for business req

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Layer 1

Layer 2

Layer 3

Slice A Slice B Slice C

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

"How to implement an architectureinside a codebase?

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

ArchitectureVS.

Codebase

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

"How to implement an architectureinside a codebase?

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

"How to enforcean architectureinside a codebase?

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Code analysisJDepend

Sonar

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Demo

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

SonargraphFormerly known as SonarJ

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Demo

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

A plain Javabased approach

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Layer 1

Layer 2

Layer 3

Slice A Slice B Slice C

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

….${layer}.${slice}VS.

….${slice}.${layer}

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Layers firstLeaks slice internals

Lower layers visible to everyone

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

"Start with less packages and the least visibility possible…

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Layer 1

Layer 2

Layer 3

Slice A Slice B Slice C

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Layer 1

Layer 2

Layer 3

Slice A Slice B Slice C

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Slices firstStart with package per slice

Expose interfaces and domain typesKeep implementations private

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Slices firstEncapsulates business moduleInternals understood anyway

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Subsystems

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

BackgroundRisk mgmt. at German public bank

Quite a few other SpringSource clients

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

"The smallest plugin systemever!

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Host

SPI SPI SPI

Plugin Plugin

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

ContextNo OSGi

Spring basedBuild-time composition

Don‘t touch the host system

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Host

Plugin Plugin

App

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

"How to make the host aware of the plugins?

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

"How to dynami-cally collect Spring beans of a given type?

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

classpath*:META-INF/spring/plugin-context.xml

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

classpath*:META-INF/spring/plugin-context.xml

SPI SPI SPI

META-INF/spring/plugin-context.xml

META-INF/spring/plugin-context.xml

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

@Componentpublic class MyComponentImpl implements TransferService {

private List<MyPlugin> plugins;

@Autowired public MyComponentImpl(List<MyPlugin> plugins) { this.plugins = plugins; } …}

public interface MyPlugin {void doSomething();

}

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Demo

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

XML?Back in the days

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

(XML?)Back in the days

Probably not a big deal anymore

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Easy access?

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

@Componentpublic class MyComponentImpl implements TransferService {

private List<MyPlugin> plugins;

@Autowired public MyComponentImpl(List<MyPlugin> plugins) { this.plugins = plugins; } …}

public interface MyPlugin {void doSomething();

}

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

@Componentpublic class MyComponentImpl implements TransferService {

// Constructor omitted

public Result myMethod(SomeParameter parameter) {

// Select the first one to match to invoke?// Select multiple ones to invoke?// Select and fallback to one if none found?// Select and throw an exception if none found?

}}

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

PluginsSelection criterionCallback method

Let the implementation decide

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

RegistryEquipped with plugins

Common access patterns

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

public interface Plugin<T> {

public boolean supports(T delimiter );}

public interface PluginRegistry<S extends Plugin<T>, T> {

T getPluginFor(S delimiter);T getPluginFor(S delimiter, T default);<E extends Exception> T getPluginFor(S del, E exception) throws E;

List<T> getPluginsFor(S delimiter);…

}

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

@Componentpublic class MyComponentImpl implements TransferService {

private PluginRegistry<MyPlugin, String> plugins;

@Autowired public MyComponentImpl(PluginRegistry<MyPlugin, String> plugins) { this.plugins = plugins; } …}

public interface MyPlugin extends Plugin<String> {void doSomething();

}

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

@Componentpublic class MyComponentImpl implements TransferService {

private final MyPlugin defaultPlugin = new MyDefaultPlugin();

public Result myMethod(String parameter) {// Select the first one to match to invoke?… = plugins.getPluginFor(parameter);// Select multiple ones to invoke?… = plugins.getPluginsFor(parameter);// Select and fallback to one if none found?… = plugins.getPluginFor(parameter, defaultPlugin);// Select and throw an exception if none found?… = plugins.getPluginsFor(parameter, new RuntimeException());

}}

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

OrderAwarePluginRegistryRespects @Order/Ordered

OAPR.reverse()

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Bells‘n‘whistlesFactoryBean

Spring namespaceLazy-eval

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Hera

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Herahttp://hera.synyx.org

Apache 2.0Soon to be on GitHub

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Spring Integration2

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

<bean class="….FirstSamplePlugin" /><bean class="….SecondSamplePlugin" />

<int:channel id="input" /><int:channel id="output" />

<int-hera:dynamic-service-activatorinput-channel="input" outputChannel="output" plugin-type= "….MyPlugin" method= "myBusinessMethod"delimiter="payload" invocation-arguments= "payload" />

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Demo

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Take-awaysKnow your dependencies

On every granularityStart as strict as possible

Get lenient where necessary

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

Thanks & creditsEoin Woods - Talk @ InfoQ

© 2011 SpringOne 2GX 2011. All rights reserved. Do not distribute without permission.

ResourcesSourcecode @ GitHub

Sonargraph

Recommended