J2EE SIG Presents: Where to Place Business Logic?

Paul Dorsey, Dulcian, Inc. - J2EE SIG Chairperson
Blaise Ribet, Oracle Corporation

About the J2EE SIG

 

The J2EE SIG is the first SIG jointly sponsored by IOUG, OAUG, ODTUG, and Oracle Corporation. It brings together IT professionals from the entire Oracle community interested in building, administering and deploying better web applications on the J2EE technology stack. The webpage of the SIG can be found at

 

Look for presentations by members of the J2EE SIG at Oracle conferences and user group meetings.

Also, please visit the J2EE SIG web page for links J2EE related resources including the ODTUG JAVA-L List Serv where J2EE topics are discussed: http://www.odtug.com/2005_J2EE.htm

 

 

About this Paper

The Steering Committee of the J2EE SIG wanted to prepare a series of “best-practices” white papers.  Each white paper would summarize the consensus of the steering committee and propose a standard for J2EE development.  Unfortunately, there is not yet even a consensus about what the right questions are, let alone the right answers. We found that, just as there is no clear industry standard for J2EE application development, there was a similar lack of consensus within the J2EE Steering Committee.  

 

Therefore, we decided to publish papers that present more than a single point of view.  If people have different opinions about the right answer to a question, each person would be invited to contribute a part of the paper.  This way, readers will be able to simultaneously read about multiple perspectives on each question posed.

 

The committee compiled a list of important questions to answer regarding where the database industry is going with J2EE and other topics of interest to the Oracle user community related to the J2EE technology stack. For the third paper, the committee selected the question: Where should the business logic go?

 

This paper represents two separate viewpoints regarding the approach to building user interfaces for J2EE-compliant systems. The first is provided by Dr. Paul Dorsey, President of Dulcian, Inc. and the chair of the J2EE SIG.  The second perspective is offered by the Oracle product management team.

 

 


Where Should the Business Logic Be Placed?

Dr. Paul Dorsey, Dulcian, Inc.

How and where to support application logic has traditionally been a hotly debated topic in the application development community. In client/server development, we only had to decide what logic should reside in the database and what logic should be written within the user interface. Within the J2EE environment, there are many more places where logic can reside. Logic can be placed in the View layer at the client, implemented in the Controller or Business Services layer running in the middle tier or enforced in the database itself. With all of these options, the question remains: Which logical rules should be enforced where? This paper examines some of the alternatives and the reasons for choosing one over another.

Frequently, complex validation is placed in database locations such as triggers on tables, INSTEAD OF triggers, or complex views. Complex data validation can also be implemented within ADF BC classes. With this additional option, it becomes difficult to set guidelines for what circumstances lead you to place data validation logic in the database as opposed to placing it in the ADF BC components.

In an environment that is not 100%Java, placing validation in ADF BC components may be dangerous. Some applications will access the validation through ADF BC, whereas other applications written in different products may not even have the ability to access the validation logic through ADF BC. If you are working in a completely Java-based environment, JDeveloper makes the creation and manipulation of ADF BC components easy enough that you may choose to use ADF BC over server-side validation. However, this is only appropriate if you can guarantee that all data-modifying DML operations will use the ADF BC components.

The main reason to be cautious about middle-tier implementation of logic is performance. There have been some catastrophic project failures caused by excessive round trips between the application server and the database.  In one case, several hundred million dollars was wasted building a month-end batch system that ended up requiring 26.5 years to execute. At my own company, we built an application with all of the logic in the middle-tier. In the first system version, a tree refresh took 13 minutes. After moving the logic to the database, we achieved sub-second response.  For one of our clients, a simple batch routine written by an expert Java programmer took 20 minutes to execute; re-writing the same routine in the database using bulk SQL commands executed in .2 seconds.   

In a client system where we took over maintenance debugging code was added to indicate how many round trips each screen was taking.  Some screens required hundreds of round trips to the database.  By moving the logic to the database, each of those was reduced to a single round trip.  On those screens with many round trips, complex SQL was being sent to the database from the middle tier.  Not only was the SQL poorly written (Java programmers are not known for their SQL skills), the screens were sending twice as much informat6ion to the database in the SQL queries, as they were receiving. 

Putting Logic in the database

The database itself provides some level of enforcement for what objects can be stored and how they are structured, along with some validation of attribute values and referential integrity.

There are also advantages to implementing some, if not all, business logic directly in the database. Business logic in the database is always enforced. It will be enforced even at a SQL*Plus prompt. Business logic implemented in the ADF BC layer will only be enforced in applications using that layer. The most critical business logic should be implemented in the database or implemented redundantly in the database and an ADF BC layer. The remainder of your business logic can be implemented in the ADF BC layer alone if you choose to do so.

Advantages of a Database-Centric Approach

Using a database-centric approach to creating applications has the following advantages:

·         This approach is the most comfortable for existing Oracle developers. It uses basically the same philosophy as creating any front-end application for an Oracle database.

·         The system is not closely tied to the UI architecture. Most of the non-UI code resides in the database. For example, programs that do not access the ADF BC layer will still use the code in the database, because all of the business rules reside in the database. As the architecture evolves, there is less code to re-factor.  Every release of JDeveloper has required us to completely rebuild our ADF BC layer.  If we had extensive logic in the middle-tier, this would have been a more painful task. 

·         Almost all ADF BC work can be supported through the JDeveloper wizards. Little hand-coding is required. The ADF BC project for an application module can be built in a few hours or less because you are only using one default entity object definition for each database view.

·         Data intensive code will run faster (often dramatically faster). The new bulk operations in SQL provide performance benefits that no procedural language can touch. Well-written database code on bulk operations will outperform database-intensive Java code by 10 to 100 times. 

·         Refactoring code as SQL and PL/SQL is much easier when the code resides in the database.  Refactoring SQL in the middle tier is usually painful.

 

Disadvantages of a Database-Centric Approach

The following are some of the disadvantages of creating applications using a database-centric approach:

·         This approach ignores all of the power and flexibility of ADF BC. With entity objects and view objects, the two new layers of abstraction sitting on top of the database are not used by this development strategy.

·         This approach does not support ADF BC reuse. One of the key elements of the ADF BC architecture is the ability to build and reuse ADF BC projects.

·         You do not take advantage of the ADF BC cache. This is one of the main strengths of ADF BC, because it offloads database activity to another location and thus saves the CPU cycles of the database server to fulfill its primary purpose, namely to manage data. The ADF BC layer can cache rows and maintain consistency with the database. This reduces the number of network messages and the amount of database activity required to serve data that has already been served.

·         You do not take advantage of ADF BC’s support of web and business tier servers. ADF BC supports the J2EE notion that there is a benefit to splitting out some of the application code to another server. If the database is called upon to handle application code, its efficiency to fulfill the primary directive will be compromised by having to handle complex business logic.

·         Your application is heavily tied to the Oracle DBMS idea of views with INSTEAD OF triggers. You cannot use this approach to build cross-database applications unless the other database provides a structure similar to views with INSTEAD OF triggers.

·         You need both Java, SQL and PL/SQL experts on your development team.  In  Java shops, this can be a problem.

 

Putting code in the application server (middle tier approach)

Coding in the application server is usually done using Java in the J2EE environment and VB.net or C# in the .Net environment.  PL/SQL is not usually used in middle tier coding.

Many developers see placing data in the database as “old fashioned”.  It is clearly “cool” to move all of your application code into the middle tier (the “cool” way to say “application server”). But if you want your application to run quickly, scale well and actually work, you should be careful about moving too much into the application server.

If your code needs to access the database, it will have to get that data over the network.  In most cases, this should not take very long; but if you are processing millions of records, grabbing each one over the network one at a time can turn a smoothly running application into an unusable program.

It is possible to pull lots of logic into the middle tier and still have a fast running application.  If you can move all of the data you need into the middle tier using a minimum of round trips, perform complex processing and push relatively little code back to the database, then moving your code to the middle tier may actually improve performance. 

In practice, this is very difficult to accomplish since it relies on the benefits of partitioning work away from an overworked database server to offset the cost of unnecessarily moving data around.  Such a benefit is only realized if your database server is being heavily utilized, which is not a common situation.

The main reason to move data into the middle tier is that your developers are Java or .Net programmers who don’t know how to program well in the database.  A lack of skill is not a good reason for placing data in the middle tier.

There is some amount of code that should be placed in the middle tier.  Code used by the user interface will perform better in the middle tier.   

Business Services Layer

Application logic can be enforced in the architecture of the business services layer, typically implemented using ADF BC or TopLink in the Oracle environment. This can also be supported through hand-coding of Enterprise JavaBeans or other third party tools to provide the same level of business rule enforcement as exists in an Oracle database.

In ADF BC, view objects are not simply default images of the entity objects, but often gather information from multiple entity objects simultaneously. In fact, view objects need not be based on entity objects at all, but can instead cache database data directly. One entity object and association can then be shared by many (5–20) different packages containing extra associations, view objects, view links, and application modules. Simple programs usually have one application module for each program; however, it is not uncommon for a program to have more than one application module, or for two programs that accomplish similar tasks to use the same application module.

 

Controller Layer

In the Controller layer, frameworks such as Struts support the logical manipulation of pages within an application.  Rules of this type do not lend themselves to database storage and should usually be placed in the Controller layer.  However, even here there are alternatives.  For example, enforcing some data validation rules that would prevent navigation out of a page could either be coded in Java in the Struts framework or written as a database function that is then called by the Struts framework.    

 

View Layer

Client-side (View layer) coding involving languages like JavaScript can be used to enforce business rules. This should be done very carefully (and rarely).  By adding code to a web application, you can greatly increase the size of the application, causing it to load very slowly.  Making round trips from the client to the application server or database usually takes (at least) a significant fraction of a second, making multiple round trips impossible.

 

Advantages of the Middle Tier Approach

The following advantages can be gained using this approach:

·         ADF BC caching, project reuse, and independence from the database are useful aspects of this approach.

·         If used correctly, this approach may afford some development efficiencies because of the modularity of the persistence/business logic layer.

·         Takes advantage of ADF BC’s ability to offload activity from the database server.

·         Offloading some work from the server can be accomplished, but only if you code very well.  A poorly written middle tier-centric application can place a greater load on the database than a database-centric application.

 

Disadvantages of the Middle Tier Approach

The following are some of the disadvantages of this approach:

·         It is a conceptually difficult approach because the system business rules may reside in different places such as tables, entity objects, or view objects. Standards and guidelines for the use of the different code locations must be developed and enforced.

·         Organizations embracing this strategy should be careful to formalize the rules. The rules apply to the database, entity objects, and view objects. They need to answer questions such as “How will objects be constructed and how will they interact?”

·         Without careful planning, the additional flexibility afforded by ADF BC can result in systems where bugs are difficult to track down. This is because the logic error may reside in many places. Well-designed error messages can alleviate this problem.

·         If you change your UI architecture (or the architecture evolves), you will have to re-write your application.

·         Code in the middle tier requiring database access may perform poorly due to the time required to retrieve and save data back to the database.

 

Conclusions

It is just as important to understand what should not go into web-deployed applications as what should be included. As long as the development team has some requisite PL/SQL skills and is not attempting to create a database-platform independent system, whenever possible, business logic should be placed in the database, either in functions and procedures, or encapsulated as complex views (perhaps with INSTEAD OF triggers).

JavaServer Faces (JSFs) are an emerging standard. It is even possible for organizations to give up and decide to change their entire development platform to .Net. Whether through the evolving J2EE stack or the political arbitrariness of organizations, architectures change. Drastic changes in the UI architecture are protected by placing as much logic as possible into the database.

It is logically possible that using ADF BC (where data is cached in the middle tier) may result in some performance improvements over having this same logic placed in the database. However, in most cases, systems where business logic is stored in the database will outperform those where this same logic is stored in the middle tier. The industry standard (particularly in the OO community) is to pull logic out of the database and place it in the middle tier. Rarely does this strategy have any beneficial impact on system performance.

 


Implementing Business Logic in the Business Tier

Blaise Ribet, Principal Product Manager, Oracle Corporation

This section discusses the benefits of implementing most of your business logic in the middle tier (business logic tier) of a J2EE application, and reasons for implementing logic in the client or database tier. This is followed by a brief description of some of the ways that Oracle Application Development Framework (ADF) helps you implement your business logic.

 

Benefits of Implementing Business Logic in the Business Tier

The J2EE architecture separates an application into UI, middle (business logic) and database tiers. Business logic, concerned with the application’s core functionality, is independent of the application’s UI, and where data is stored. Within the business logic tier, business logic is implemented in business objects. A business object represents an entity specific to your application such as a customer, an order or a line item. Some ways to implement business objects include ADF Business Components (ADF BC) entity objects, TopLink POJOs, and EJB session or entity beans.

 

Implementing your business logic in middle-tier business objects has several benefits:

 

1. Less code to write

Implementing business logic in a business object allows you to write each rule once and leverage it anywhere that business object is manipulated by users. The same business logic could be implemented in the client tier, but this would require the rules to be rewritten in every page or form that manipulated that data.

 

2. Business logic is easier to find

If you want to find out what rules have been implemented for customers, you only need to look in the Customer business object. If your code is well-written there is no need to hunt through all your code looking for any business rules that apply to a customer.

 

3. Code is easier to maintain

Less code to write means less code to maintain. If you later decide to change or remove a business rule, there is only one place to look for it and one place to change it.

 

4. Allows validation of unposted data

Implementing business logic in the middle tier, rather than in a database stored procedure, allows any data entered by the user to be validated before the data is posted to the database. This allows for more immediate feedback – the end user can see and fix any errors before anything is posted to the database.

 

5. Allows state to be maintained across pages

Web applications often require state to be maintained across pages. You want to users of your application be able to add an item to an order and continue browsing without actually submitting the order, and frameworks such as ADF make it easier to implement this functionality. However, it’s likely that you also want to apply your business logic as the end user leaves one page and navigates to another, and implementing your business logic in the middle tier, rather than the database, allows you to do this without making a round trip to the database

 

Implementing Business Logic in the Client Tier

Developers often choose to implement at least some validation logic in the client, tier, and there are client technology frameworks to help you with this. JavaServer Faces has its own validation framework including a number of built in validators; and third-party products such as JGoodies provide validation frameworks for Swing clients.

 

Client-side validation is best-suited for simple validation that does not require database access, such as length validation or regular expression validation.

 

Implementing Business Logic in the Database

Many J2EE developers want to put only data in their database, and want their business logic centralized in the application’s business tier. There are some good reasons for centralizing business logic in the business tier: it’s good object-oriented design, and makes your code more readable and maintainable. There are also some good reasons for avoiding implementing business logic as PL/SQL stored procedures: updates to business rules may involve changing Java and database code and therefore might be harder to track; and the application becomes less portable if it relies on a lot of stored procedure code.

 

While it is generally advisable to keep business logic out of the database, this guideline is sometimes taken to its extreme, with some J2EE developers insisting that J2EE code should be completely portable between relational databases, knowing as little about the database as possible and not relying on any vendor-specific functionality. Clearly this extreme approach is not taking advantage of performance and other benefits that specific database functionality can offer, and any well-architected application should use stored procedures and triggers when appropriate.

 

There are a number of cases when it is appropriate to use database triggers and stored procedures to implement logic, including:

·         Persistence logic: logic that applies to the way data is persisted, and is independent of any application that accesses the database. Using a database trigger to assign a sequence value to a primary key is an example of persistence logic; cascade delete is another.

·         Operations that can be done much more efficiently in the database, such as bulk updates spanning multiple tables.

·         Logic used by other non-J2EE applications within the organization.

·         Existing stored procedures that can be leveraged by new applications.

 

Implementing Middle Tier Business Rules with ADF

Oracle Application Development Framework (ADF) helps you implement efficient business logic by providing tools to implement business logic declaratively; and an API that you can override to code your own business logic.

 

Most of an application’s business logic will be implemented in a business domain object. In ADF Business Components, this business object is called the entity object. This section describes some of the ways to implement middle tier business rules with ADF.

 

Declarative Validation

ADF has a declarative validation framework, making it easy for application developers to create validation rules without writing any code. A number of common validation rules are already provided, including range validation, length validation, regular expression validation. Java developers can also code custom rules which can then be registered with the framework as new declarative rules that other application developers can use.

For applications using ADF Business Components, declarative validation rules are specified for ADF BC entity objects. For other ADF applications, you can add declarative validation rules to data controls.

 

Coded Business Logic

By overriding framework methods, you can add your own business logic to standard framework behavior, including:

·         Create logic: Override ADF BC’s create() method to add custom logic when the object is created. For example, you might want to add some logic to assign a default value to an attribute.

·         Setter logic: Override the object’s setter methods to add custom logic when a particular attribute’s value is changed. For example, you might want to add logic to calculate a discount when the quantity of an order item is entered or changed.

·         Post changes logic: Add custom logic to be executed when data is posted to the database.

By exposing a set of methods to override, the framework helps you keep your code readable and maintainable. And since your business logic is coded in Java, you can make it do whatever you want to do.

 

Declarative Attribute Settings

ADF BC design-time editors allow you to apply simple business logic to individual attributes, including whether the attribute is required, whether it’s updateable, and a default value for the attribute. This business logic is then executed at run time: required values are shown with a required indicator, non-updateable attributes are displayed as read-only values, and default values are filled in.

 

Domains

An ADF BC domain is a custom data type. Validation can be added to the domain to verify that any new data fits the requirements for that custom type. For example, you could create a CreditCardNumber domain with code to verify the length and checksum of a credit card number.

 

ADF Support for Client-Side Business Logic

 

Binding Validators

ADF declarative validation is available on binding attributes as well as data control attributes. This allows you to add validation for every appearance of a particular attribute on one page or panel. In general, it is probably more useful to add rules at the data control or ADF BC entity object level, where they will apply to any page or panel that uses the attributes.

 

ADF Faces Validation

Many ADF Faces components have built-in settings that provide simple validation including minimum value, maximum value, length and whether the component is a required field. In addition, you can specify a custom validator with ADF Faces components.

 

ADF Support for Database Business Logic

The ADF framework has a number of ways to integrate with business and persistence logic in your database.

 

1. Executing PL/SQL Stored Procedures

The ADF BC framework exposes a method that you can call to implement custom logic for processing database inserts, updates and deletes. You can add custom code to call a PL/SQL stored procedure before, after or instead of executing the standard operations; in this way you can incorporate existing PL/SQL stored procedures into your ADF application.

 

2. Synchronizing with Triggers

The ADF BC design-time editors contain settings to refresh a particular attribute after it has been inserted or updated. If a value will be modified by a database trigger during an insert or update operation, you can use these settings to reflect the effects of the database trigger in the middle tier.

 

3. DBSequence Datatype

The Refresh After Insert setting is particularly useful when you have a primary key column that is automatically assigned using a database trigger, and if you specify a DBSequence datatype for a primary key attribute of this type, the Refresh After Insert setting is automatically selected for you (since primary keys are always required attributes, the DBSequence datatype also assigns a dummy primary key value when new records are created, to avoid errors).

Summary

This paper has outlined some of the benefits of placing your business logic in the middle tier while keeping a pragmatic approach to using database logic where appropriate.