How Granular Should My Application Modules Be?
About once a week, I get asked the question:
How large (or small) should my application modules be? Is it better to have one big module, or lots of littler ones?
I'm going to use this blog story as a place to keep up to date with best practice thoughts on this topic.
While we were still working on the alpha version of ADF Business Components back in 1998 -- then known as "Project Verona", later coined "Java Business Objects" (i.e. oracle.jbo.*), and finally renamed to Business Components for Java (BC4J) before first going production -- what today we know as an application module was called a workunit. We had liked the name workunit since it described what we envisioned developers using it for: to represent a logical unit of work. We later changed the name to try and come up with a term that would sound more familiar to existing Oracle Forms and Oracle Designer users, who were familiar with the Designer concept called a "module component". It represented the logical "data model" to accomplish a specific user task. So, we settled on the term application module to represent this unit of work.
In the early analysis phases of application development, often architects and designers are using UML use case techniques to iteratively refine a high-level description of the different kinds of end-user functionalities that the system being built will need to support. We initially envisioned that for each high-level, end-user use case identified during this design phase, that there would be the following kinds of logical outputs:
The domain business objects involved
In other words, what core business data was relevant to the use case?
The user-oriented view of business data required
In other words, what subset of columns, what filtered set of rows, sorted in what way, grouped in what way, was needed to support the use case?
The identified domain objects involved in the use case helped know which ADF entity objects would participate in the use case. The user-oriented view of business data required helped developers define the right SQL queries (captured as ADF view objects) to show the data to the end-user in the exact way (and with only the minimum required details) that they need. ADF View Links allow natural master/detail relationships to be setup between these views in order to group the data hierarchical to match exactly the kind of end-user experience you want to offer the user to accomplish the use case.
The application module is the "workunit" container that includes instances of the reusable view objects required for the use case in question, indirectly related to the underlying business domain objects -- the ADF entity objects -- whose information the use case is presenting or modifying.
Use cases map to modular functions. Certain higher-level functions might "reuse" a "sub function" that is common to several business work flows. ADF supports the ability to create software components that mimic this natural modularity by creating application modules that you can reuse inside of other application modules. While this feature of "nesting" or reusing an instance of one application module inside of another is in practice a feature that many users don't discover on their own, it is one of the most powerful design aspects of the ADF Business Components system.
Using the basic logic that an application module represents an end-user use case or work flow, you can build application modules that cater to the data required by some shared, modular use case, and then reuse those application modules inside of other more complicated application modules that are designed to support a more complex use case.
At runtime, your application works with a "main" or what we call a "root" application module. Any application module can be used as a "root" application module, however in practice the application modules that are used as root application modules are the ones that map to a more complex end-user use case -- assuming you're not just building a straightforward CRUD application -- and they may contain other nested application modules that participate in the same transaction, and share the entity caches, of the root application module in which they are nested. This transaction and entity cache sharing is handled for you automatically by the ADF framework.
So, in short, the answer to the original question about "how big (or small) should my application modules be?" is that they should be as big as necessary to support the specific use case you have in mind for them to accomplish. They can be assembled from finer-grained application module components using the nesting feature above.
Since a complex business application is not really a single use case, a complex business application implemented using ADF will typically not be just a single application module.
At runtime, each top-level application module that your application uses will get an application module pool created for it.More sophisticated customers like Oracle Applications who are building large applications with many, many business functions, often have written custom code to make more efficient use of a "generic" pool of container application modules to avoid ending up with hundreds of different application module pools. Based on the customer workflow that needs to be started, they have written code that takes a generic application module -- which is basically an application module with no view object instances of its own or any nested application modules of its own defined at design time -- and they programmatically use the createApplicationModule() API on this "generic" application module to dynamically nest an instance of the appropriate "use case"-based application module at runtime. When the user is done, they call remove() on that dynamically nested application module instance, leaving the generic application module "empty" again, ready to be used by another end-user for whatever "use case" they need to accomplish.
In the case of a demo application like the ADF Toy Store, there is really only one main use case that it is implementing which is browsing for items to purchase and checking out your shopping cart. You could argue that these are two small use cases, but I decided to keep the demo simpler by treating them as a single unit. Had I expanded the demo to also support back-end type "store inventory management" functionality, I would definitely model that as one or more additional use cases and create separate application module(s) to support them.
NOTE: If you have additional questions related to this topic, please email me so I can expand what this document covers to address them, too.