510 likes | 652 Views
to be announced. Rod Johnson Interface21 Oslo, September 15, 2005. Escaping the Technology Cycle. Rod Johnson Interface21 Oslo, September 15, 2005. Topics. The challenge Java/J2EE technology evolves at a rapid rate Don’t want to re-implement applications every 2 years
E N D
to be announced Rod Johnson Interface21 Oslo, September 15, 2005
Escaping the Technology Cycle Rod Johnson Interface21 Oslo, September 15, 2005
Topics • The challenge • Java/J2EE technology evolves at a rapid rate • Don’t want to re-implement applications every 2 years • The core of enterprise systems should endure for 5-15 years • How do we preserve our investment? • Can we benefit rather than suffer from technology developments?
Pace of change • Recent quote from a manager at a client • Managing Java projects is tough for us -There’s a new version of everything every 9 months • This is exciting for many developers, but worrying for managers • Particularly problematic for large projects • Technology environment may change during the lifetime of the project
Pace of change • Perceived difficulty keeping up with evolution of platform tools, frameworks and practices • Technology risks accompany each migration • Developers have a natural instinct towards the latest and greatest • But constant migration is just not possible in most enterprise projects • If enterprise Java is to inherit the mantle of the mainframe, it must deliver stability and longevity
Uncertainty • Platform evolution • Specifications • Server versions • Library evolution • Projects can have many dependencies • Each dependency evolves • Interaction between dependencies • Tool evolution • Poor record of backward compatibility • Tools-reliant projects can be severely impacted • Evolution of development practices
Uncertainty • Open source • Offers a huge positive contribution to projects, but… • Has a particularly rapid rate of change • Tends to force users to update • Absence of support contracts as a given for the software
Pace of change • Contrast to mainframe era • Things change every decade • Things always work as documented • Everything is backwards compatible • Infrastructure is taken out of service very slowly • Challenge is that mainframe systems are often what we need to replace in enterprise Java applications • So what if our technology is sexier • It must promise similar longevity
Approaches to solving the problem • Discipline • Commercial relationships • Standards • Better technology
Discipline • This depends on what you do yourself • Need to show restraint • Don’t deliberately chase the bleeding edge • Choose products that are proven • Don’t build an unduly complex ecosystem with complex interactions between its parts • Don’t view open source as a free for all
Commercial approaches • Can a relationship with a vendor insulate against technology change? • Server vendors (IBM, BEA, JBoss etc) • Stack integrators (SourceLabs, SpikeSource etc) • Other product vendors (Interface21 etc) • Important and solves some issues • Insulates against impact of minor version changes • Reduces risk of adoption, increases changes of success • Provides early exposure to product roadmap • Ensures adequate training etc. • But the J2EE experience has shown that even powerful vendors cannot insulate their customers from change effectively
The standards experience • EJB 1.1 • EJB 2.0 • EJB 3.0 • JDO 1.0 / 2.0 • Java Persistence API
Standards experience • Not very successful for programming model • Goals of standardization • Create competition in implementation, rather than competition of potentially incompatible ideas • Help to achieve critical mass of adoption, skills, documentation etc. • Ensure interoperability • Preserve investment through contributing to longevity of technology • First 3 points have largely succeeded • Although open source has also succeeded in these areas • Last point has failed
Standards experience • EJB and persistence standards do not offer any clear migration path • Have not delivered future proofing • Future proofing taken to mean just backward compatibility • Old programming model still works • But new one is incompatible • Proliferation of programming models • Product bloat
Better technology • Maybe quality and conceptual basis of technology matters more than standardization • We need discipline, vendor relationships and a standard for the basic platform, but the technology probably matters most • Whether a technology is invasive is more important than whether it is standard • Invasive technologies • Depend on their environment directly • Constrain code written to work with them • Typically API-centric • New generation of POJO-based technologies avoid these pitfalls
Haven’t we heard this before? • This generation of frameworks will solve everything • …Yeah, right • Why it’s different • Modern frameworks are designed to conceal themselves • New concepts (Dependency Injection and AOP) allow for new possibilities
POJO • POJO stands for Plain Old Java Object • A POJO is not bound to any environment: • No imports of classes that bind it to a specific environment • Only uses framework classes that offer good abstraction • Not dependent on a particular lookup mechanism • Collaborating instances are injected using plain Java constructors or setter methods • True POJOs are testable in isolation
We all understand what a POJO is… • But it’s time to kill the POJO terminology • Something so important should not be defined in terms of what it’s not • Most importantly, the concept is not specific to Java • Identical model in C# or other OO languages • PONO • Spring.NET offers identical PONO-based programming model • POSLO? • Plain Old Some Language Object
The POJO is dead:Long live the object “POJO” was a crutch while we freed our minds of “old J2EE”. We should be able to cope with thinking in objects now.
Enabling technologies Power to the POJO Portable service abstractions AOP IOC
Dependency Injection • Means that callers depend only on the interface of a service • Not the lookup strategy or the implementation details • Ideal point of pluggability • Can switch between implementations without affecting callers • Eliminates implicit dependencies on environment such as JNDI • Standard Java methods can be called by a container in any environment • Can be called without a container environment • We have cut back to the language, not the runtime • We depend only on business concepts
Dependency Injection in Practice public class MyClient { public void setWeatherService(WeatherService ws) { this.weatherService = ws; } ... <bean id="weatherService" class="spring...SimpleRemoteStatelessSessionProxyFactoryBean" > <property name="businessInterface" value="...WeatherService" /> <property name=“jndiName” value=“ejb/weatherService” /> </bean> <bean id="myClient" class="...MyClient" autowire="autodetect" /> • No service locator or “plumbing” code
Switch to Local POJO <bean id="weatherService" class="...DefaultWeatherService"> <property name="countryCode" value=“47" /> <property name="dataSource" ref="dataSource" /> </bean> • Change to a single bean definition • No change to Java code
Switch to Web Service <bean id="weatherService" class=“spring...HessianProxyFactoryBean"> <property name="serviceUrl" value= " http://server:8080/weather" /> <property name="businessInterface" value="...WeatherService" /> </bean> • Again, change is localized • Callers simply work with the business interface • Zero “plumbing” code
Implications for testability public void testForMyClient() { MyClient mc = new MyClient(); mc.setWeatherService(myMockService); // Test mc } • Imagine how much harder testing would be if we hadn’t use DI to factor out the JNDI lookup and EJB API calls…
Aside: Testing • Unit testing must test objects in isolation • Concentrates on business logic • Testing is a special case of taking code out of context • We always want to take an object out of context to write a unit test • If an object can be unit tested easily, it’s probably insulated sufficiently from infrastructure concerns
AOP • Dependency injection takes us a long way • Can remove all configuration mechanisms from code • But what about infrastructure concerns that affect the execution of many business methods, such as transaction management or security? • Dependency Injection alone is not enough
AOP • Enter AOP • AOP can remove infrastructure dependencies from main code base • Allows us to evolve infrastructure independently of code base
Examples: AOP • Case study: Transaction management • Local transaction management • API-centric • Dependent on environment • Global transaction management with JTA UserTransaction • API-centric • Dependent on environment • EJB CMT • API-centric (EJB) • Dependent on environment • AOP: Transaction aspect • Transactional behaviour is externalized from mainline logic
Example • Update database with new Person domain object • Using JDBC • Single database, want to deploy in a web container such as Tomcat…
Local transaction management public void update(Person p) throws SQLException { Connection con = null; PreparedStatement ps = null; try { con = getLocalConnection(); PreparedStatement ps = conn.prepareStatement( "UPDATE PERSON SET NAME=? WHERE ID =?"); ps.setString(1, p.getName()); ps.setLong(2, p.getId()); ps.execute(); conn.commit(); } finally { if (ps != null) { try { ps.close(); } catch (SQLException ex) { } } if (conn != null) { conn.close(); } } } Local transaction
JTA UserTransaction public void update(Person p) throws SQLException { ADDD DAO ********************** Connection con = null; PreparedStatement ps = null; try { DataSource dataSource = getJndiDataSource("java:comp/env/jdbc/myDataSource"); con = dataSource.getConnection(); PreparedStatement ps = conn.prepareStatement( "UPDATE PERSON SET NAME=? WHERE ID =?"); ps.setString(1, p.getName()); ps.setLong(2, p.getId()); ps.execute(); } finally { if (ps != null) { try { ps.close(); } catch (SQLException ex) { } } if (conn != null) { conn.close(); } } } JNDI and JTA dependency
EJB CMT public class PersonManager implements SessionBean { public void setSessionContext(SessionContext ctx) ... public void ejbCreate() ... public void update(Person p) throws SQLException { Connection con = null; PreparedStatement ps = null; try { DataSource dataSource = getJndiDataSource("java:comp/env/jdbc/myDataSource"); con = dataSource.getConnection(); PreparedStatement ps = conn.prepareStatement( "UPDATE PERSON SET NAME=? WHERE ID =?"); ps.setString(1, p.getName()); ps.setLong(2, p.getId()); ps.execute(); } finally { if (ps != null) { try { ps.close(); } catch (SQLException ex) { } } if (conn != null) { conn.close(); } } } } EJB, JNDI and JTA
Spring transaction management, injection private DataSource dataSource; public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } public void update(Person p) throws SQLEXception { Connection con = null; PreparedStatement ps = null; try { con = this.dataSource.getConnection(); PreparedStatement ps = conn.prepareStatement( "UPDATE PERSON SET NAME=? WHERE ID =?"); ps.setString(1, p.getName()); ps.setLong(2, p.getId()); ps.execute(); } finally { if (ps != null) { try { ps.close(); } catch (SQLException ex) { } } if (conn != null) { conn.close(); } } }
But that wasn’t really a Spring example… It was a Java example
Custom AOP • Transaction management comes out of the box with Spring • But you can also externalize custom aspects from your core business logic • Auditing • Caching • Security • Same key benefit • Eliminate code duplication • Allow infrastructure and core business logic to evolve independently
Evolution beyond the API • Actually more powerful • JMX example • Providing an MBean interface • Is static • Is work • Consider legacy code • What happens when infrastructure issues add up? • Transaction management • Security • JMX • …
Portable abstractions • Portable abstraction is essential • To sit behind aspects • To cover corner cases when you do need an API • Sometimes transaction management is part of business logic • Abstraction must deliver decoupling • Abstraction can run in many environments • Abstraction has minimal dependencies • Focuses on task in hand (transaction management) • Abstraction must offer simple, usable programming model • These goals are not effectively delivered by J2EE standards
Spring data access example public interface PersonDao { void update(Person p) throws DataAccessException; } public class JdbcPersonDao implements PersonDao { private JdbcTemplate jdbcTemplate; public JdbcPersonDao(DataSource ds) { this.jdbcTemplate = new JdbcTemplate(ds); } public void update(Person p) throws DataAccessException { jdbcTemplate.update( "UPDATE PERSON SET NAME=? WHERE ID =?", new Object[] { p.getName(), p.getId() }); } } Decoupled from JDBC
Practical steps to preserve your investment • Build a domain model of POJOs • (Whoops, objects) • Build a service or application layer of objects • View remoting as a façade layer • Don’t built remoting into the fabric of the application • Objects should know as little as possible about infrastructure • Avoid frameworks or environments that impact your objects • Including your own frameworks
Architectural picture Remote exporters Presentation tier JSP, JSF, Velocity, Jasper Reports… Middle tier definitions Service objects / Business Facades (analogous to SLSBs) Transactional boundaries Domain objects Spring web-tier context DAO interfaces DAO implementations RDBMS JDBC/ ORM
Domain model • Represents the core investment of your project • Major effort to develop but should produce ROI • Should not be unduly constrained by the technology platform • If it is, question the technology platform • We must react to changes in the business model • Driven by the business • Don’t want to dance to the tune of changing infrastructure • Driven by things and people that want to cost the business money
Domain model practices • Use POJOs • Avoid frameworks that have a strong impact on your domain objects • Entity beans • Including your own frameworks! • Use whatever technology your O/R mapping tool provides to hide tool-specific code • Hibernate interceptors, User Types
Service/Application Layer practices • Avoid dependency on environment-specific APIs such as JNDI • Avoid dependence on framework APIs
Dependency Injection public class MyClient { public void setWeatherService(WeatherService ws) { this.weatherService = ws; } private WeatherService getWeatherService() throws RemoteException, NamingException { try { WeatherServiceHome home = (WeatherServiceHome) jndiLookup("ejb/WeatherService"); return home.create(); } catch (CreateException ex) { throw new ServiceLocationException(ex); } } }
Traditional EJB / JNDI approach public class MyClient { public void setWeatherService(WeatherService ws) { this.weatherService = ws; } private WeatherService getWeatherService() throws RemoteException, NamingException { try { WeatherServiceHome home = (WeatherServiceHome) jndiLookup("ejb/WeatherService"); return home.create(); } catch (CreateException ex) { throw new ServiceLocationException(ex); } } }
Annotations: Dependencies by the back door? • Annotations should express concepts, not implementation strategies • Otherwise annotations can pollute of valuable business logic with fleeting infrastructure concerns • Annotations make a good target for pointcuts • To express concepts that don’t change unless business logic changes • Transaction management • Questionable use of annotations • @Inject for Dependency Injection • Unnecessary • Ties to a particular lookup strategy • Tied to the concept of a lookup strategy • “Autowiring”
Reality check • But what about all the integration and wiring? • Aren’t we still dependent on the environment? • Don’t we need configuration? • Wait, we already had configuration • We always need configuration • The runtime structure of the application will need to change as technology evolves • …but that’s a lot less costly than revisiting all Java objects
Technology change can be a positive • Decoupling allows independent evolution • Framework/environment can evolve independently of application code • We can benefit from change • Your code can run better with better infrastructure • Spring transaction aspect integration with WebLogic transaction management • Frees your code from dependency on BEA proprietary APIs
Summary • Decouple code from its environment • Key enabling technologies • DI • AOP • Portable service abstractions • Core investment is in domain model and other business logic • This must be shielded from volatile infrastructure • If we follow these guidelines, technology evolution can be a benefit rather than a threat