None of of us enjoy spaghetti code, much less spaghetti builds, spaghetti tests, or spaghetti classpaths. Some days software engineering seems like the struggle against spaghetti - modern projects often become a large and complex tangle of source code and resources, and the runtime interactions are even worse! This means many projects are hard to navigate, difficult to extend and problematic to deploy/run. You only have to look at the OpenJDK itself to see the problems it faces in trying to have a smaller deployment and runtime footprint! Jigsaw was to be the inbuilt solution for the OpenJDK, extending beyond the JVM itself to help applications with their modularisation story (i.e. Jigsaw or OSGi). Sadly, Jigsaw is not going to make it for Java 8, so developers are left with only a few tooling choices in order to help them. However, tooling is only part of the answer in managing the complexity. What really matters in avoiding a noodly mess is the layout of your source code and resources, clear contracts, and how you think about the dependencies your code has at runtime. Dr Holly Cummins and Martijn Verburg will take you through some of the practical design decisions you can take to help modularise your application properly, independent of tooling. Time permitting they'll then showcase some of tooling support that OSGi can bring to the table as the premier modularity system for Java today.
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
Everything I know about software in spaghetti bolognese: managing complexity
1. Everything I know about software I
learned from spaghetti bolognese
Managing complexity
Holly Cummins, IBM
@holly_cummins
Martijn Verburg, jClarity
@karianna
2. What do we know about software?
Holly Martijn
11 years with IBM CTO - jClarity
WebSphere Diabolical Developer
JVM performance Community Cat Herder
5. Understanding interfaces
My users don't need to know about all my methods
●
I'd like to swap this implementation for that
●
implementation
6. Understanding reuse
“Could I re-use some your code in my project,
please?”
●
Inheritance vs Composition
●
Inheritance ~= Liskov Substitution Principle
●
Composition ~= Does Type B only want only
some/part of the behavior exposed by Type A?
7. Services
Normal
spaghetti
bolognese
Vegetarian
spaghetti
bolognese
8. Getting hold of implementations
Perpetual problem
●
Factories
●
●
Factory factories
●
Factory factory factories
●
Factory factory factory factories
Home-rolled frameworks
●
META-INF/Services
●
OSGI services
●
9. Dependency injection
Externalised Factory Problem
●
Enable implementations to be switched in and out
●
●
Avoids hard-couplings in runtime
●
Enables effective testing and test-driven-development
●
Implementations can be stubbed or mocked out
●
Really helps modularity
●
Guice, Picocontainer are light-weight starting points
10. What can I do?
●
Be strict about dependency management
●
Understand external and internal interfaces
●
What do you want to be able to swap?
●
Think about what type of re-use you're going for
●
Draw out dependencies
●
Tooling can help
12. Problems with JARs
●
JARs are transparent
March12, 2010 QCon London 2010 Ian Robinson 12
13. Problems with JARs
●
Java Platform Modularity
Classes encapsulate data Jar
●
●
Packages contain classes
Package
●
Jars contain packages
Class
●
Class visibility: Package
●
private Class
Class
●
package private
Package
●
protected
Class
●
public Class
●
No “jar scoped” access modifiers.
March12, 2010 QCon London 2010 Ian Robinson 13
14. Problems with JARs
●
No means for a jar to declare its
dependencies. Jar
Package
●
No versioning. Class
Package
Jars have no modularization
Class
● Class
characteristics Package
Class
Class
●
At runtime there is just a collection of
classes on a global classpath
March12, 2010 QCon London 2010 Ian Robinson 14
15. More problems with jars
●
In a normal jar, an implementation is just as easy to
use as the interface.
●
In a normal jar, an implementation easier to use than
the interface
●
No worries about factory patterns
●
Encourages consumers to bust encapsulation
wide open
March12, 2010 QCon London 2010 Ian Robinson 15
20. Understanding dependencies
●
What other code does my code touch?
●
When does it connect?
●
Compile time?
●
Runtime?
●
Transitively?
●
Only at test?
31. Choose the right granularity
●
A common approach
●
foo-api
●
foo-core
●
foo-ui
●
Outsiders only rely on foo-api (interfaces!)
●
It boils down to your domain modeling.
●
Naming is everything
33. What can I do?
●
There is a bunch of tooling to help
●
Maven, Ant/Ivy
●
OSGi, Jboss Modules
●
Nothing beats a whiteboard or a drawing pad
●
TDD should be Test Driven Design
●
Pair Programming? Think Pair Designing instead
34. Versioning
Now that you have modules, how do you manage the
relationship between them?
March12, 2010 QCon London 2010 Ian Robinson 34
36. Versioning
●
Major increment: I break consumers
●
Removal of existing methods or interfaces
●
Minor increment: I break implementers
●
Addition of methods to interfaces
●
Micro increment: I promise I don't break anything
●
“Clear” defect fixes
●
March12, 2010
Internal improvements
QCon London 2010 Ian Robinson 36
37. Versioning
●
But … causes developer depression
●
Compatibility != amount of work
●
Tempting to use marketing versions rather than
semantic versions
●
A good example here is Java itself!
March12, 2010 QCon London 2010 Ian Robinson 37
38. What can I do?
●
major.minor.trivial
●
SNAPSHOT is acceptable internally
●
If you have customers/clients
●
You need to think about backwards compatibility
●
Plugin systems are useful here
●
Once more think dependency injection
March12, 2010 QCon London 2010 Ian Robinson 38
46. OSGi
●
Explicit dependency management
●
Classloading
●
Explicit version management
●
Services
●
No more hacky factories
47. OSGi
●
Enables
●
Reliability
●
No more ClassDefNotFoundException
●
Small footprint
●
Dynamism
●
Easy to get started with – it's just simple manifests
●
It's compatible too!
48. OSGi Manifests
Manifest is a bit like a recipe
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: MyService bundle
Bundle-SymbolicName: com.sample.myservice
Bundle-Version: 1.0.0
Bundle-Activator: com.sample.myservice.Activator
Import-Package: org.apache.commons.logging;version="1.0.4"
Export-Package: com.sample.myservice.api;version="1.0.0"