Jakub is a Java EE developer since 2005 and occasionally a project manager, working currently with Iterate AS. He's highly interested in developer productivity (and tools like Maven and AOP/AspectJ), web frameworks, Java portals, testing and performance and works a lot with IBM technologies. A native to Czech Republic, he lives now in Oslo, Norway. Jakub is a DZone MVB and is not an employee of DZone and has posted 154 posts at DZone. You can read more from them at their website. View Full User Profile

Book: Real World Java EE Patterns – Rethinking Best Practices (Review & Digest)

06.16.2010
| 19752 views |
  • submit to reddit

I’d like to make you aware of the excellent book Real World Java EE Patterns – Rethinking Best Practices by Adam Bien (blog), a Java Champion and renowned consultant, software architect and Java EE standardization comitee member. I’d absolutely recommend it to any architect or developer serious with Java EE 5 or 6 development, even to those not planning to use EJB 3.x (at least prior to reading the book :) ). It’s a must-read complement to the now a little outdated Core J2EE patterns as it updates the patterns for the new bright world of EJB 3/3.1 while discarding some of them and introducing some new, extremely useful patterns and techniques.

The book starts with an overview of the evolution of Java Enterprise Edition and the hard issues it solves for us, continues with the new and updated patterns and strategies and concludes with an introduction of two opposite architectures you can build with Java EE 5/6, namely lean SOA and domain-driven (which itself makes it worth reading).

What I really appreciate in addition to that valuable content is that for each pattern there is a section on testing and documentation and a really good evaluation of consequences in terms of maintainability, performance and other such qualities. You will find there also many code samples and beautiful applications of the Builder and Fluent API patterns.

The main message is that EJB 3.x is so lean and powerful that we must justify why NOT using it – and when using it, you should be very pragmatic and only introduce patterns, layers and principles if they bring real value.

A summary of the patterns

Because not only abstractions but also my memory is leaky :-) , I’ve written down the key points as a reference and a reminder. It will be of a rather limited value to anybody else as it’s closely bound to the structure and content of my mind, yet I hope it could give you a good idea of what is inside the book and why you should go and pick it up immediately :-) .

A general rule: “An introduction of another layer of abstraction or encapsulation causes additional development and maintenace effort.” [p137] Thus it must provide some real added value to be justifiable.

Notion: New or radically different patterns are marked with *

BUSINESS TIER

Service Facade (Application Service?!)

  • [JH: The old name should likely be Session Facade, not A. S.]
  • The boundary class used by UI
  • A transaction boundary too (SOA: starts a new tx)
  • Coarse-grained API
  • Usually @Stateless
  • Either contains a simple business logic (i.e. is merged w/ a Service) or delegates to Services/DAOs (incl. EntityManager)

Service (Session Facade?!)

  • [JH: The old name should likely be Application Service, not S.F.]
  • Fine-grained, reusable logic in an EJB with local access only, product of decomposition
  • Used by a Service Facade
  • Usually @Stateless s Tx=Mandatory
  • Uses EntityManager and/or specialized DAOs
  • In SOA arch. w/ anemic objects the behavior is here contrary to the PDO below

Persistent Domain Object (Business Object)*

  • Rich domain object, ie. having rich behavior/bus.logic and persistent (x anemic structure of SOA)
  • Forces:
    • Complex business logic
    • Type-specific behavior necessary (profits from inehritance, polymorphism) – e.g. validation rules are domain object related and sophisticated
    • DB may be adjusted for JPA needs
  • Solution: @Entity; getter/setters only when justified (x anemic structures, i.e. state is hidden), has methods modeling behavior and changing its state (creating other entities..); methods named fluently (domain-driven API)
    • Only the cross-cutting/orchestration logic impl. in a Service
    • Created/maintained by a Service, S.Facade or Gateway (CR(U)D methods)
    • Requires the entity to stay attached => buz.+present. tier in the same JVM

Gateway*

  • Provides access to the root PDOs, exposes them to the present. tier (opposed to S.Facade, which hides the logic impl.)
  • It’s necessary to manage PDOs who’re unaware of EntityManager and to hold client state (the PDOs) over conseq. executions
  • The presentation tier must be in the same JVM
  • Essential for the (rich) domain-driven architecture
  • Forces:
    • PDOs are already well encapsulated, additional encaps./layering unnecess.
    • DB may be changed as needed
    • changes of UI are likely to affect DB anyway
    • An interactive app., w/ non-trivial validations depending on objects’ state
    • Users decide when their changes are persisted, when not
  • Note: Not much suitable for RIA UI for they’re running on the client = remotely
  • Solution: @Stateful w/ Extended persist. context and tx=NONE and a single save() method that only starts a tx. (via annot. tx=Req.New) and thus forces Ent.Man. to commit changes performed so far
  • Consequences:
    • Scalability: Doesn’t scale as well as stateless but still absolutely sufficient for most apps; depends on cache size, length of sessions; need to find out via load tests
    • Performance may be better as PDOs are loaded only once and accessed locally per ref.
    • Need a well defined strategy for handling stale objects, i.e. the OptimisticLockException, test early
    • Maint.: “In non-trivial, problem-solving applications, a Gateway can greatly improve the maintainability. It simplifies the architecture and makes the intermediary layers superfluous.” [114] Unsuitable for SOA arch.w/ many externally exposed services.
    • Productivity, ease of use much higher

Fluid Logic

  • Inclusion of scripting for algorithms/bus.logic that change often so that recompilation/redeployment aren’t necessary – JSR-223 (Scripting for the Java Platform)
  • Executed from a Service

Paginator and Fast Lane Reader

  • A Service/S.F. allowing for efficient access to large amounts of mostly read-only data [subset]
  • Former motivation: in EJB 2, a FLR accessed huge quantities of read-only data via JDBC directly for efficiency – JPA is efficient enough in this, providing a way to extract only some attributes and paginate over large results
  • Valid motivation: “JPA is not able to stream objects, rather than load the entire page into memory at once. For some use cases such as exports, batches, or reports direct access to the database cursor would provide better performance.” [123]
  • Forces: iteration over large amount of data needed; it cannot be sent at once to the client and must be cached on the server; the client needs only some attributes of the entity; the access is mostly read-only
  • Solution – not a single one but different strategies w/ +/-
    • Paginator and Value List Handler Strategy: sess. bean implementing an Iterator of list of lists of domain objects (a list = a page); either Stateful holding internally the current position or Stateless; uses Query.setFirstResult + setMaxResults. May use Persist.Ctx.EXTENDED to be updatable.
    • Live Cursor and F.L.R. Str(eaming?): to get as fast access as possible when conversion into objects isn’t necessary, we may let inject DataSource via a @Resource directly into an EJB and use JDBC; will share Connection w/ any Ent.Mgr. in the same tx
  • Paginator in a domain-driven arch.: “A Paginator is also an optimization, which should only be introduced in case the iteration over a collection of attached PDOs causes performance or resource problems.” [p269]

Retired Patterns

  • Service Locator – replaced by DI
  • Composite Entity – JPA entities completely different
  • Value Object Assembler – VOs mostly not needed anymore as entities are POJOs; partly impl. by EntityManager
  • Business Delegate – not needed thanks to DI injecting a Business interface’s impl., which doesn’t throw EJB-specific, checked exceptions anymore
  • Domain Store -impl. by the EntityManager
  • Value List Handler – implemented by EntityManager; it can also execute native SQL and convert them to entities or a list of primitives

Integration Tier

Data Access Object (DAO)

  • The J2EE 1.4 motivation for DAOs doesn’t apply anymore:
    • JPA EntityManager is a DAO
    • Encapsulation of a DB is leaky anyway; you will only rarely change your DB vendor and never a RDBMS for another storage type
  • Thus DAOs are only needed for non-JPA resources and at those rare occassions, where they provide a real added value, such as consolidating often repeated persistence logic to support DRY – or if you application has some special requirements that really justify the effort.
  • Solution: A stateless EJB with @Local interface and @TransactionAttrbute(MANDATORY), accessed by Services/S.Facades.
  • Note: Heavy use of JPA QL would blur the business logic so it might be better to move the creation of queries into dedicated query builders or other utility classes.
  • Strategies (may be combined together, of course):
    • Generic DAO – the results of JPA queries aren’t type-safe and a type-safe generic DAO (CrudService) for CRUD and named query search operations (such as <T> T create(T t)) could be more convenient.
      • Suggestion: Use entity class constants for named query names to avoid typos [and help to track their usage].
    • Domain-specific DAO – DAO for a particular entity, which provides an added value aside of wrapping JPA, such as prefetching of dependant objects, managing common relations, results filtering based on the current user etc.
    • Attached-result DAO – the default behavior – JPA entities stay attached for the duration of the transaction and any changes to them will be commited to the DB
    • Detached-result DAO – if it isn’t possible to stay attached, e.g. due to the data source’s limitations. A common case in JEE is to return a subset of managed entity object graph mapped to transient DTOs for optimization purposes (select new BookLiteView(…) ..).
    • Back-end Integration DAO – encapsulates a Java Connector Architecture, Common Client Interface or similar adapter for a legacy resource to shield the developer from their low-level APIs.
    • Abstract DAO – reusable data access logic can be also inherited instead of delegated to a helper DAO. Purists could complain but “Inheriting from generic DAO functionality streamlines the code and is pragmatic.” Especially suitable for DB-driven apps.

Transfer Object (TO) and Data Transfer Object (DTO)

  • Again, the J2EE 1.4 motivation for (D)TOs doesn’t apply anymore because detached Entities aren’t active elements and are POJOs
  • There may be few reasons where (D)TOs may be appropriate:
    • To provide consumer-specific views to the persistence layer/send a subset of the data graph for performance reasons (see the Detached-result DAO above)
    • To keep outside-facing services binary compatible, which may be necessary for long-lived SOA services that share the same domain model and need to be evolved independently. Adding/changing an entity field needed by a new service isn’t possible if the entity is used also by older services/clients.
      • At times it may be necessary to decouple SOA services by replacing hard references to other entities with DTOs that carry their ID and type and act as a proxy for fetching those entities via their own services. Of course this is laborious to code/maintain and less efficient due to multiple service calls so you need a sound reason to justify it.
    • Transfering data from non-JPA sources.
    • To transfer also presentation tier-specific metadata for building UIs on the fly (e.g. @LAbel(“Enter password”), @MinLength(4))
    • To provide a simpler form for transfer over RESTFul/SOAP/CORBA/or even ASCII
  • Solution: A Serializable or Externalizable POJO. (Implementing Externalizable allows for providing faster to process and smaller serialized forms and may (should) be automated via code generation. But use with care – it adds lot of code that must be maintained and understood.)
  • Strategies
    • Builder-style TO – fluent API simplifies its constructions and makes it easier to read. Ex.: MyDTO d = new MyDTO.Builder().name(“Duke”).age(42).build(); (Builder is a nested static class)
    • Builder-style Immutable TO – prescribe the setting of certain attributes – mark them final and only instantiate the DTO when build() is invoked.
    • Client-specific TO – add metadata e.g. for dynamic UI construction and data validation [you likely don't want them in domain Entities] – annotations such as @Label(“First Name”) are added to the DTO’s getters (getFirstName()) . Check JSR-303 Bean Validation.
    • Generic DTO – dynamic (basically a map of attributes), using reflection – for generic UIs. Cons: not type-safe, several times more objects (attribute name, type representation, metadata ..); see Apache BeanUtils.

Legacy POJO Integration

  • If you need to integrate a legacy POJO into a JEE application and it needs to leverage the container services (e.g. security, lifecycle and concurrency management, DI) and participate in transactions, you can simply turn it into s Stateless session bean provided that it complies with the EJB 3 programming restrictions (has the default constructor and, prior to 3.1, an interface). Instead of adding annotations to its source code, which may be not accessible, you use ejb-jar.xml.
  • The overhead introduced by turning it into an EJB is really low and comparable to other DI frameworks.

Generic JCA

  • “It is not possible to access legacy resources such as files, native libraries, or starting new threads from EJBs without violating the programming restrictions.” [p181] – see Chapter 21.1.2 of JSR 220
  • Even if you do not care about violating those restrictions, you may care for making your application non-portable.
  • Thus if you want to access a Java EE incompatible resource, perhaps transactionally, in a portable way, you need to use JCA (with the additional benefit of monitoring)
  • The JEE restrictions do not apply to Servlets, MBeans and JCA connectors, of those only JCA can participate in transactions and within a security context.
  • While complete JCA implementation is complex, a minimal one is “surprisingly simple” – it comprises of 2 interfcase, 4 classes, 1 XML file. Two of the classes are highly reusable, the remaining part is resource dependent.
  • You don’t even need to implement the Common Client Interface (CCI), which may be too abstract and complex, and provide your own one instead.
  • Depending on your requiremements, you can choose which parts of JCA to implement [JH: perhaps e.g. javax.resource.spi.work when dealing with threads]
  • Example: transactional file access:
    • a Connection {write(String), close() } interface (JCA is connection-oriented) and Connection factory interface to be put into JNDI: DataSource extends Serializable, Referenceable { getConnection() }
    • a (simple) logic in the class FileConnection impl. Connection and javax.resource.spi.LocalTransaction, delegating close() to the GenericManagedConnection (below) and using JCA’s ConnectionRequestInfo for implementing hashCode and equals to distinguish this connection from others
    • a simple FileDataSource class impl. DataSource providing a custom ConnectionRequestInfo implementation (e.g. with equals returning true and hashCode 1 to make all connections equal) and using JCA’s ConnectionManager to create a connection, casting its output to FileConnection, using the C.M. and a ManagedConnectionFactory supplied via the constructor
    • a generic GenericManagedConnection class impl. ManagedConnection and LocalTransaction (to invoke the F.C.’s corresponding methods), which will actually instantiate the FileConnection and manage its listeners, while also providing a custom impl. of ManagedConnectionMetaData to describe it and returning null for getXAResource. Notice that the app. server uses the event notification to manage the connection.
    • a generic GenericManagedConnectionFactory class impl. ManagedConnectionFactory, Serializable and creating the FileDataSource as the conn. factory and GenericManagedConnection as the ManagedConnection. (matchManagedConnections selects a connection with matching ConnectionRequestInfo from a set of candidates or throws a ResourceException.)
    • an ra.xml file (def. by the specs) containing all the interfaces and classes under resourceadapter/outbound-resourceadapter/connection-definition (managedconnectionfactory-class=GenericM.C.F., connectionfactory-interface=DataSource, connectionfactory-impl-class=FileD.S., connection-interface=Connection, connection-impl-class=FileC., transaction-support=LocalTransaction, authentication-mechanism/a.-m.-type=BasicPassword and /credential-interface=javax.resource.spi.security.PasswordCredential)
    • Finally you pack it all into a .rar JAR, drop it to the server, and configure a connection pool and deploy the data source under some JNDI name, e.g. “jca/FileDS”, to make it injectable via @Resource(name=”jca/FileDS”)
    • Note: Apache Commons File Transactions contains XA-compliant file access and could be easily wrapped w/ this connector
  • “a partial implementation of a JCA adapter could be easier and faster than an attempt to build a comparable solution from scratch” [p195]

Asynchronous Resource Integrator (Service Activator)

  • Invocation of a Service from a Message-Driven Bean (invoked by a messaging system via JMS), bound to a Topic (1/N:M) or Destination (1:1)
  • Prior to EJB 3.1, Service Activator was a work-around to invoke a business method asynchronously by calling it via a MDB, now we’ve the much simpler @Asynchronous method/type annotation
  • Since EJB 3.1, MDBs are only necessary for integration of front-end or back-end asynchronous clients/resources
  • The MDB’s task is to extract the “payload” (usually an Object, Text or BinaryMessage), convert it into meaningful parameters, forward it to a Service and handle errors and “poison messages” (wrong type/content leading to an exception and reprocessing of the message) correctly. It should contain no business logic.
    • A container starts a transaction before onMessage and removes the message when it ends w/o a rollback
  • Note: Some messaging providers such as openMQ provide REST-ful interface (yet not standardized, but watch amqp.org) and can be thus invoked from a presentation or client (browser – ajax) tier
  • “The importance of integration tests in an environment identical to production cannot be emphasized enough.” [p201]
  • MDB: “… proper error handling is hard and the debug process a real challenge”[p201]
  • Strategies
    • Front-end Integration – asynch. messages from the presentation or client tier, likely Ajax; the payload is usually XML/JSON
    • Back-end Integration – usually a legacy system; usually can’t influence the message

Infrastructural Patterns and Utilities

Patterns that can be used at any layer or are not of architectural significance yet very useful.

Service Starter

  • Initialize an EJB upon server start (e.g. to load a cache)
  • EJB 3.1: @Singleton with @Startup. May also @DependsOn another one.
  • pre-EJB 3.1: a HttpServlet with init() method and load-on-startup 1

Singleton

  • Standardized in EJB 3.1 with @Singleton (in the scope of a single JVM only)
  • By default uses @Lock(LockType.WRITE) and thus can only be accessed by a single thread at a time; user READ for concurrent access
  • Strategies (rather uses)
    • Gatekeeper – limit access to a legacy resource (e.g. due to limited # of licenses or its limited scalability) – this could be done in a JCA adapter but that’s a lot more work. It can also serialize access to a single-threaded resource with LockType.WRITE
    • Caching Singleton – holds a cache of mostly read-only data, likely initialized at startup, and accessed concurrently thanks to LockType.READ

Bean Locator – encapsulates JNDI if DI not available (e.g. Stateful EJB can’t be injected into a servlet).Use a Fluent GlobalJNDIName Builder to simplify the error-prone process of global JNDI name construction.

Thread Tracker – name a thread after the bean and business method it’s currently executing for easier monitoring/troubleshooting (instead of e.g. “http-0.0.0.0-8180-1″) via an interceptor (but beware that the interception is several times slower than a direct call)

Dependency Injection Extender

  • Integrate another DI fwrk’s managed beans into an EJB via a custom Interceptor, which will invoke the DI framework to inject its beans into the EJB upon each call (e.g. via Guice’s Injector.injectMember(invocationCtx.getTarget());)
  • The interceptor must ensure proper bean’s lifecycle w.r.t. its scope (request x session x …)
  • Strategies:
    • Stateful Session Bean Injector – can use per-instance injectors and cache the injected components for the EJB’s lifetime
    • Stateless Session Bean Injector – either all the members must be injected before each call or it’s necessary to use smart proxies able to react e.g. to transactions for non-idempotent components
    • Transactional Integration – “the injected components already participate in a transaction started in the session bean”
  • Performance – interceptors and DI rely on reflection which is slower than direct calls, yet still much faster than an average DB access

Payload Extractor – factor out the (reusable) type checking and error handling for a MDB message into a reusable interceptor; poison messages moved by the interceptor to a “dead letter queue” via a stateless EJB using the JMS API

Resource Binder – put a custom resource into JNDI using a @Singleton with @Startup and the JNDI API (Context.(re)bind()). Notice that your app. server’s proprietary JNDI impl. may enforce some restrictions on the resource object (such as serializability).

Context Holder – you want to pass some context data yet not to add it as a param to each method on the call tree (S.Facade > Service > DAO, indirectly PDO) => use the standard @Resource TransactionSynchronizationRegistry, with the actual context set perhaps by an interceptor. Notice that ThreadLocal may be problematic if a S.Facade invokes a Service and each is from a distinct thread pool = diff. thread.

Pragmatic Java EE Architectures

There are two opposite approaches, with best practices in one being anti-patterns in the other: the SOA architecture and he Domain-driven architecture. Which one is better depends in your requirements.

Lean Service-Oriented Architectures (online article)

  • JEE 5/6 can be used to build the leanest SOA impl. possible – (nearly) no XML, no external libraries, frameworks, only a JAR with a short persistence.xml, even more so in 3.1 where we can drop the @Local interfaces (though that makes testing more difficult)
  • SOA implies coarse-grained, distributed, stateless, atomic, self-contained, independent services with a procedural nature
    • Though in JEE, local access shall be always preferred when possible (performance)
  • Building blocks:
    • Service Facade – @Stateless EJB with TransactionAttribute=REQUIRES_NEW – acts as a remoting and transaction boundary, hides implementation details while providing coarser-grained interface
    • (optional) Services (with @Local and tx=MANDATORY) – implement the actual logic in a procedural way; in simple cases, the Facade may directly use a DAO to avoid a dumb Service w/o any added value
    • (optional) DAOs (incl. EntityManager) – as needed
    • Anemic persistent data structures – entities only hold data exposed via getters/setters, w/o any behavior
      • “Although the anemic object model is considered to be an antipattern, it fits very well into an SOA. Most of the application is data-driven, with only a small amount of object-specific or type-dependent logic.” [p260] Plus, for simple apps, they’re easier to develop, can be generated, can be detached and sent to a client who won’t get access to any business method (but beware the lazy-loading issue).
    • Transfer Objects – an essential pattern, a SOA service must stay binary compatible even if its domain objects change (e.g. a field added, needed by a new service) and thus can’t expose directly JPA entities
  • The contract, represented by the Service Facade’s @Remote interface and the TOs and visible to clients, is strictly separated from its realization
  • Suitable e.g. if there are multiple different clients (i.e. not only a single web UI)
  • Essential complexity of SOA
    • “SOA aims for reuse, which causes more overhead and requires additional patterns. Service components are, on average, more complex than comparable domain components.” [p264]
    • The object graph sent to a client is detached (and serialized) => we must merge the changes when receiving it back, this is complex => added methods to update only parts of the obj.graph => code bloat [p101] – “The essential complexity of service-oriented applications is the synchronization of the PDO graph with the persistent store.” [p266] Both writes (client updates a part of the object graph, which must be merged back) and reads (because of unavailability of lazy-loading) are difficult.
    • Lazy loading of detached objects (in the present. tier) impossible => must know/request in advance what to load (=> code bloat)

Objects- or Domain-Driven Design (online article)

  • As opposed to SOA, it relies mainly on well-defined encapsulated (persistent) objects with state and behavior and tends to be stateful.
  • Building blocks:
    • Entity – the (behavior-rich) Persistent Domain Object pattern. “A real domain-driven architecture should actually only be comprised of Entities with aspects.” [p256]
    • (optional) Control – a Service/DAO – implements cross-cutting aspects (Entity-independent, reusable logic and orchestration of multiple PDOs) – often for reusable queries, data warehouse jobs, reports etc.; used only exceptionally in DDD
    • Boundary – a Gateway – the border between the UI and the business logic, exposes PDOs as directly as possible; usually stateful (to keep PDOs attached); “only necessary because of the Java EE 5/6 shortcomings … In an ideal environment, a Gateway could also be implemented as an aspect, or even a static method on a PDO.” [p266]
    • (optional) TO – used for optimization purposes when there is a real need
  • Contrary to SOA, here is no separation between the specification and the realization (which is pragmatic, requires less effort)
  • “The main advantage of the stateful domain-driven approach is the transparent synchronization and lazy loading of dependent entities.” [p267] [JH: Also, with direct access to PDOs, it's much easier to implement and evolve the UI - see Seam. We could say this is (much) more productive and "agile" than SOA.]
  • Essential complexity of DDD
    • DDD requires a stateful Gateway holding a reference to an attached root PDO – “The statefulness itself isn’t a scalability problem, rather than the amount of attached entities during the transaction.” [p266] (every entity used will stay cached till the session ends)
    • “… you will have to think about freeing the resources and detaching superfluous PDOs. This could become as complex as the synchronization of detached entities or loading of lazy relations in a service-oriented component.” [p267]
    • => perhaps necessary to tune the cache settings or use proxies (e.g. OIDs/References) instead of actual objects and load objects as needed.
    • “Whether the aggressive caching behavior of your provider becomes a problem or not depends on many factors, including the number of concurrent sessions, the session length, and the number of accessed PDOs per session.” [p267]
  • It’s necessary to find a good compromise regarding the coupling of different (sub)domain PDOs (such as Address, Customer), i.e. between independence of components and ease of use. We must also deal with circular dependencies (think of bidirectional dependencies) between PDOs and thus components. Be pragmatic:
    • “Few bidirectional dependencies between components are harmless.” [p268] – especially considering the unnecessary laboriousness and complexity of possible workarounds
    • You can use a proxy that resolves the object on demand using a service, as SOA does, but this is not very transparent; “it actually only obfuscates the dependency between two entities” [p268]
    • The favourite solution is to refactor/restructure your components to get the related PDOs into one, though that breaks the “maximal cohesion” principle

Notes on Terminology

  • The term “anemic domain model” originates likely from Martin Fowler
  • The term “Domain-Driven Design” has been made popular by Eric Evans via his book Domain-Driven Design: Tackling Complexity in the Heart of Software, published 2003
From http://theholyjava.wordpress.com/2010/05/08/book-real-world-java-ee-patterns-rethinking-best-practices-review-digest/
Published at DZone with permission of Jakub Holý, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Thomas Eichberger replied on Wed, 2010/06/16 - 5:21am

When I read the book the first time, I was quite disappointed, because it stated only obvious things.

The next times I read it, I liked it more, but I'm really not sure what I should think about it. For beginners, it's probably too complicated or confusing, or they probably don't understand everything and even don't notice what they've been missing. For experts, most parts are well known, so there's not much new, just some of Mr. Bien's special names and terms.

Nevertheless I would recommend to read it and work through it. It's still the best book in this area.

Mladen Girazovski replied on Wed, 2010/06/16 - 6:45am

Couple of questions..

ValueObject(VO, TransferObject(TO or DTO) - They are they same thing (VO was later renamed to TO, since ValueObject was already used in DDD for something different), why do they both appear in this Article(ValueObjectAssembler)?

Are both those terms used in the book?

Apart from that i am dissapointed at how many times the term DDD is used, but apparently the concepts behind were not really understood, most of those "patterns" here are technology centered. "Gateway" is not an DDD term, but this Artcile pretends it was:

Essential for the (rich) domain-driven architecture

 The correspondig DDD Pattern/term is ApplicationService, which is an Facade, but the article pretends it is something different:

Provides access to the root PDOs, exposes them to the present. tier (opposed to S.Facade, which hides the logic impl.)

 There seems to be more inconsistencies in this article (not sure if they are from the book), this could be because some well-known pattern names where re-coined or some new ones were invented and replaced old ones...

Jakub Holý replied on Thu, 2010/06/17 - 5:37am in response to: Thomas Eichberger

@Thomas Eichberger:
Well, still there is a number of people between beginners and experts who can easily understand the book and also find there new insight. For example me :-)

Jakub Holý replied on Thu, 2010/06/17 - 5:55am in response to: Mladen Girazovski

@Mladen Girazovski:

Hi Mladen, thanks for the review. You are right that VO and TO are the same thing, I'm not sure why A. Bien uses "ValueObjectAssembler"  when the original pattern is "Transfer Object Assembler" .

Regarding:

"Gateway" is not an DDD term, but this Artcile pretends it was: Essential for the (rich) domain-driven architecture

This is a misunderstanding. Gateway isn't an essential part of DDD, but it is essential for the implementation of DDD in Java EE. Gateway is necessary to make the rich objects accessible to the presentation tier: "PDOs are passive. It is not possible to access them directly without an execution context." [page 101] And: "Nevertheless, the Boundary [JH: the Gateway] in the domain-driven setup is only necessary because of the Java EE 5/6 shortcomings. At least a single active component (a session bean) is needed." [p. 266]

You may want to read Adam's article Domain-driven design with Java EE 6 - An object-oriented architecture for interactive applications, which explains it in detail.

Mladen Girazovski replied on Fri, 2010/06/18 - 10:33am

Hi Mladen, thanks for the review. You are right that VO and TO are the same thing, I'm not sure why A. Bien uses "ValueObjectAssembler"  when the original pattern is "Transfer Object Assembler" .

Problably just a mistake, ValueObject was renamed to TransferObject, you can still find Docs on the net that use the old "ValueObject" term(example: http://java.sun.com/j2ee/patterns/ValueObject.html), DDD defined the ValueObject earlier, with a different meaning.

 This is a misunderstanding. Gateway isn't an essential part of DDD, but it is essential for the implementation of DDD in Java EE. Gateway is necessary to make the rich objects accessible to the presentation tier: "PDOs are passive. It is not possible to access them directly without an execution context." [page 101] And: "Nevertheless, the Boundary [JH: the Gateway] in the domain-driven setup is only necessary because of the Java EE 5/6 shortcomings. At least a single active component (a session bean) is needed." [p. 266]

 That explains it pretty well, personally i'm not sure if there is shortcommings of the JEE platform when applying DDD.

Thanks for answering my questions and clearing my confusion confusion Jakub! 

adam bien replied on Thu, 2010/06/24 - 2:09am in response to: Thomas Eichberger

Hi Thomas,
thanks for the honest review. I saw the old J2EE Patterns (used around the year 1945 :-)) being applied in Java EE 5 over and over again. This resulted in over-engineered systems. So I started to write the book to present my point of view. In my opinion Java EE 5/6 are really simple - so it is hard to write an advance book about that :-).
I described what worked in my projects and used other names to clarify the intention (e.g. renamed ServiceLocator to BeanLocator, because it only locates beans in my case).
thanks again & enjoy the lightweight Java EE 6,
adam

adam bien replied on Thu, 2010/06/24 - 2:17am in response to: Mladen Girazovski

@Mladen,
there is a huge difference between VO and DTO: Value Object vs. Data Transfer Object
A Gateway is an Anti-Facade. It doesn't hide anything.
I'm sure not everything is consistent in my book. The reason: most of the code was extracted from working projects - and software is never perfect.
I also mentioned Value Object Assembler pattern - and retired that :-) See page 132.
If you need a copy for review to find even more inconsistencies -> drop me an email,
thanks for the meta-review (the review of the review),
adam

Jakub Holý replied on Mon, 2010/07/12 - 6:06am in response to: adam bien

@Adam

Thank you for the link, I knew I've seen somewhere an explanation of the difference between VO and DTO, just couldn't remember where. I could have perhaps guessed it was in your blog :-)

Thomas Eichberger replied on Sat, 2010/07/17 - 11:26pm in response to: adam bien

@Adam

Yes, maybe I started to read the book with wrong expectations. Don't know exactly why I'm not so happy with the book, even though I usually like and enjoy your blog and your articles very much.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.