CS636 Thinking about Layers

Examining the Pizza and Music systems that will be the basis of future projects.    You should read this before the midterm exam.

Here are some coding rules to set up serious client-server applications (and later, web applications) using layering, applicable to pizza1, and music1, pizza2, and (in the future) the webapps pizza3 and music3. Note that “business logic layer” is just another name for “service layer”. Let us know if you disagree with any of my interpretations in the following.

The layers

  1. System.in and System.out are only for talking to the user, only in the presentation layer.  This means no System.out.println's in the lower layers, except temporarily for debugging.
  2. Don't ever call System.exit() from anywhere but main().  Instead, generate an exception to tell the top-level app what's going on.
  3. The business layer service APIs should be able to handle all the needed actions for the apps in the presentation layer, i.e., the apps should not call the DAO APIs directly.
  4. The DAO should provide all the DB actions needed by the business/service layer, in a way natural to the business layer requirements.  No SQL knowledge should be needed by the business logic programmer.  
  5. No service or DAO object should construct another service or DAO object (to follow IOC, inversion of control pattern), and the service and DAO objects should all be set up by special code.
  6. Errors in the DAO layer should throw SQLException (or, for JPA implementations, JPA’s subclass of RuntimeException), caught in the business logic layer and usually rethrown as ServiceException. 
  7. Errors in the business logic layer should throw ServiceException, caught in the presentation layer.
  8. Don't call up to a higher layer (i.e., use an upcall): we are using pure call-down layers.
  9. Consistent with the earlier rules, as much code as possible should be pushed down from the presentation layer to the logic layer.  The presentation layer has the minimal code needed to interface to the user.
  10. Consistent with the earlier rules, all database handling code should be pushed down to the DAO layer from the logic layer.  However, the DAO code should make no business decisions. The facts from the data should presented by the DAO to the BL, and the BL should be completely in charge of specifying changes to the database.
  11. We are using a “stateless service layer”, in the sense that the service layer code (and DAO code) has no fields holding domain data across multiple service layer calls.  The presentation layer is allowed to hold domain data across multiple service calls (it's user-private).

Domain Objects

  1. Many domain objects represent (as "scratch copies") entity instances in the database, or data on the way to the database, and should have a unique id "id" that corresponds to its PK in the database.
  2. However, not all data from the database needs to be represented by domain objects.  The ones that are needed are the ones that are natural to the business layer coding needs.  Domain data can be held in simple ints, Strings, etc., as for example the current day number in Pizza.
  3. Domain objects may have related information from the database in addition to what is in the entity table row.  In particular, Sets can hold multi-valued attributes or other N-1 related data for the entity instance. They can be Sets of other domain objects or just Sets of Strings, say.
  4. Domain objects may be created in the service or DAO layer (from database data). They should not be created or modified in the presentation layer.
  5. Domain objects can move across layers, carrying data around.  They do not themselves constitute a layer in the sense of the three layers discussed above, but since the heart of the webapp is the service layer, the domain objects are most closely tied to the service layer.
  6. Some domain objects such as Cart in the music project, help represent data for one user not yet committed to the database.
  7. If a domain object (one directly related to database data) has business-method mutators (used after its original creation), it is a good idea to provide another invariant object (a “transfer object”) to carry the database-related data to the presentation layer, as PizzaOrderData does for PizzaOrder. This is especially true if there are multiple presentation layers using the system, with different subsets of needed data. Note that this is a best practice, not always heeded in the rush of development (i.e., you can send Invoices to presentation in music1, for example, without losing credit.)

For pizza2 and music2 (and for future):
     1. All database statements are inside of some transaction.
     2. Transactions are started and committed or rolled back in the service layer, because it's in charge of the business logic and transaction boundaries are important to the semantics of application actions.
.   3.  A transaction must never include user input or output. Thus the service layer needs to finish a transaction before returning from its service-API call.
    4.  It is particularly important to mark local helper methods as private in the service layer.  They don't need to start a transaction because (usually) one should already be in progress when they are called.