Java IoT Authors: Zakia Bouachraoui, Pat Romanski, Elizabeth White, Liz McMillan, Yeshim Deniz

Related Topics: Java IoT

Java IoT: Article

AOP, IoC, and OO Design Patterns Without Frameworks

Finding the right balance

I'd like to share some of the design highlights of a large-scale content distributing system I worked on a while back. Some of the highlights may seem trivial; some may be a little more complicated. To me, software design is a matter of finding a balance between applying available technologies and fulfilling real-world requirements and constraints. The goal of design is always to ensure both the runtime and development-time quality of the software.

I'll be using two of the components from the project, Scheduling Management Component (SMC) and the Data Access Layer (DAL), for purposes of illustration. The function of SMC is to monitor the database and detect any newly added or updated content, and schedule that content for delivery based on some business logics. The DAL, as its name implies, provides data access services.

Extensibility by OOP Patterns and Principles
In the early design phase of SMC, we quickly lay out some of the candidate classes, as well as the relationships among them. In UML notation, class details are omitted at this stage. Figure 1 shows some of the major classes. The classes are by no means final, and neither are the relationships. We're trying, however, to capture the business requirements as much as possible.

We've designed the Schedule-Manager class as the façade of this component. It exposes external APIs. Other components that need to interact with SMC do so through this class. ScheduleManager is also in charge of managing the lifecycles of classes inside SMC.

One of the business requirements is that the first production release of the software won't support clustered deployment, but it will in later releases. One of the keys to supporting clustering is managing the states of the component instances deployed across the clustered nodes so that they're always in sync. Keeping this in mind, we decide to centralize the cluster-sensitive states of all the SMC classes into one class rather than having each class manage its own states. This results in a SchedulingContext class. This class knows how to save and retrieve various states of the component. When the time to support the cluster comes along, instead of having to open up each class and make changes, all we have to do is change the SchedulingContext class - that modifyies the way this class accesses states so that all the clustered instances share the same states, virtually or physically.

The UML diagram in Figure 2 shows some major classes after introducing the SchedulingContext class.

One issue we immediately notice with this design is the tight coupling between the SchedulingContext class and the classes that depend on it. As you can see, quite a number of classes depend on the SchedulingContext class. If we have to change the SchedulingContext class for any reasons (fixing bugs, adding new business features, switching to other application server, etc.), chances are we also have to make changes to the dependent classes.

Following OO best practices, interfaces are good at promoting loose coupling. In fact, it's always a good idea to code to interfaces rather than concrete classes (another simple yet powerful OO principle). The solution is simple enough - we abstract the scheduling context by making SchedulingContext an interface. We also want this interface's client to be unaware of the actual implementation, and the GoF Abstract Factory Pattern does the job.

The design of the Scheduling Context is shown in Figure 3. When it comes time to support clustering, we can do it with little programming. It makes it a lot easier to maintain the software after it goes into production. We also avoid vendor lock-in by shielding the cluster-sensitive implementation, which is likely to be vendor-specific.

Another consequence of moving the states of an individual class into SchedulingContext is that we can now design other stateless classes, which is good because:

  • A stateless class is thread-safe, avoiding potential issues in a multithreading environment (which SMC is)
  • Generally speaking, stateless objects scale better
  • Stateless classes are easier to maintain

Note that, at this point, ScheduleManager and SchedulingContent are acting together as the "container" of the other classes in the sense that:

  • The ScheduleManager class intercepts all client calls to the component
  • The ScheduleManager class manages the lifecycles of other classes
  • The SchedulingContext interface provides a gateway to access component states

This is intended and, as you'll see later, we'll use the container-like feature of these two classes more in our design.

Decoupling with IoC Pattern
So far, everything is pretty simple and straightforward. What else can we do to make the design better?

With the current design, unit testing isn't a trivial task. Let's take the FNDTaskPuller class as an example. Listing 1 shows the simplified version of this class. For demonstration purposes, let's assume this class has a business method, someBizMethod().

To test this class, we'd create a test class similar to the one shown in Listing 2.

What's the problem with this code? We're testing SchedulingContextSimpleImpl (which is the concrete class of SchedulingContext) indirectly. But we really mean to test the FNDTaskPuller class. This isn't right. As we all know a unit test should never go outside of its own class boundary.

Furthermore, it's hard to control the states of the SchedulingContextSimpleImpl in order to test the different behaviors of FNDTaskPuller class.

In practice, a common technique to overcome this kind of tight coupling is using mock objects, which can assist in separating unit tests. Mock objects themselves, however, require extra coding efforts. This extra coding effort can be significant, buggy, and cause maintenance problems. What more? Developers have to replace mock objects with real classes at deployment.

The reason for this problem is the way we acquire the reference to the SchedulingContext object in the FNDTaskPuller class. In this case, the FNDTaskPuller class is asking for a reference to a SchedulingContext object. Explicitly.

To get around this, we need to change the way we obtain an object reference. This is where Inversion of Control (IoC) comes into play.

With IoC, objects obtain references to their dependent objects passively. The IoC container literally "injects" the dependency into the classes.

Now, we need an IoC container for our design to wire the objects. We have the choice of using an existing container product or building our own. Normally in-house framework building is considered a bad practice because of its complexity and inefficiency. However, we decided to do it anyway after carefully figuring out what we really needed. Some of the reasons are:

  • We don't intend to build a framework that supports complete IoC features. Rather, our goal is to provide a feasible solution to our immediate problem: loosening up the coupling between SchedulingContext and other classes. At this point, some simple dependency wiring functions will do the trick.
  • The team didn't have enough experience with third-party containers when we started development, and the project timeline was a tight learning curve.
  • The team had to use some legacy code and worried that it would require some architectural modifications to integrate third-party containers with the legacy codes.
  • It's a good starting point for developers to get their feet wet on IoC concepts and implementation.

Our solution was to embed the simple dependency wiring functions in the ScheduleManager class, which, as mentioned, was already acting as the SMC "container." It also made sense to embed the IoC functions in this class. Because of the simplicity of construction injection, we refactored all the classes depending on the SchedulingContext so that they were ready for constructor injection. Listing 3 gives the FNDTaskPuller class as an example.

All we have to do in the ScheduleManager class is to instantiate a SchedulingContext object and assign it to classes that need a reference to it. If, some time in the future, a full IoC container is needed, we can just modify the ScheduleManager class.

Taking Care of Scattered Code
While designing the data access layer, we foresaw that there would be a lot of scattered "plumping" code - code that doesn't do anything related to business functions. They are only here to fulfill middleware functions: JNDI lookup, JDBC resource management, exception handling, etc. This code will spread into almost all data access objects (DAOs) and, in most cases, this code is identical method to method. We all hate scattered code because it's a maintenance nightmare, is error-prone, and makes code hard to understand.

List 2 is an example of a how we would have implemented our data access methods without AOP.

In Listing 4, only one line of the code is actually "doing something." The rest is just "plumping" code. When "plumping" code starts leaking into your application, chances are you'll find yourself hunting down all the application code when requirements change.

There's one thing we can do. While OOP makes software design modular, AOP makes code modular. And modularity is good.

Once again, we faced the choice of using an existing AOP framework or building our own. We decided not to use any of these frameworks for the same reason why we didn't use a IoC container. Instead, we separate the concerns programmatically in our code. Although this is not the most elegant, cleanest way, it's the fastest, which, in our case, is a big gain.

To separate the cross-cutting concerns from the DAOs, we came up with the following class design:

  • DAO classes. These are classes that implement data access functions. There can be an arbitrary number of DAO classes, and they're POJOs.
  • DAOFactory is the advice class. It implements the cross-cutting concerns. It also defines pointcuts, in our case, all DAO methods. It does so by handing out proxy objects of the corresponding DAO classes.

More Stories By Jinsong Yang

Jinsong Yang is a senior application engineer at Warnerbros. Advanced Digital Services, and is a Sun Certified Enterprise Architect. He has devoted the last six-plus years to designing and integrating large-scale Java EE applications. He holds an MS in computer science from UCLA.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.

IoT & Smart Cities Stories
Moroccanoil®, the global leader in oil-infused beauty, is thrilled to announce the NEW Moroccanoil Color Depositing Masks, a collection of dual-benefit hair masks that deposit pure pigments while providing the treatment benefits of a deep conditioning mask. The collection consists of seven curated shades for commitment-free, beautifully-colored hair that looks and feels healthy.
The textured-hair category is inarguably the hottest in the haircare space today. This has been driven by the proliferation of founder brands started by curly and coily consumers and savvy consumers who increasingly want products specifically for their texture type. This trend is underscored by the latest insights from NaturallyCurly's 2018 TextureTrends report, released today. According to the 2018 TextureTrends Report, more than 80 percent of women with curly and coily hair say they purcha...
The textured-hair category is inarguably the hottest in the haircare space today. This has been driven by the proliferation of founder brands started by curly and coily consumers and savvy consumers who increasingly want products specifically for their texture type. This trend is underscored by the latest insights from NaturallyCurly's 2018 TextureTrends report, released today. According to the 2018 TextureTrends Report, more than 80 percent of women with curly and coily hair say they purcha...
We all love the many benefits of natural plant oils, used as a deap treatment before shampooing, at home or at the beach, but is there an all-in-one solution for everyday intensive nutrition and modern styling?I am passionate about the benefits of natural extracts with tried-and-tested results, which I have used to develop my own brand (lemon for its acid ph, wheat germ for its fortifying action…). I wanted a product which combined caring and styling effects, and which could be used after shampo...
The platform combines the strengths of Singtel's extensive, intelligent network capabilities with Microsoft's cloud expertise to create a unique solution that sets new standards for IoT applications," said Mr Diomedes Kastanis, Head of IoT at Singtel. "Our solution provides speed, transparency and flexibility, paving the way for a more pervasive use of IoT to accelerate enterprises' digitalisation efforts. AI-powered intelligent connectivity over Microsoft Azure will be the fastest connected pat...
There are many examples of disruption in consumer space – Uber disrupting the cab industry, Airbnb disrupting the hospitality industry and so on; but have you wondered who is disrupting support and operations? AISERA helps make businesses and customers successful by offering consumer-like user experience for support and operations. We have built the world’s first AI-driven IT / HR / Cloud / Customer Support and Operations solution.
Codete accelerates their clients growth through technological expertise and experience. Codite team works with organizations to meet the challenges that digitalization presents. Their clients include digital start-ups as well as established enterprises in the IT industry. To stay competitive in a highly innovative IT industry, strong R&D departments and bold spin-off initiatives is a must. Codete Data Science and Software Architects teams help corporate clients to stay up to date with the mod...
At CloudEXPO Silicon Valley, June 24-26, 2019, Digital Transformation (DX) is a major focus with expanded DevOpsSUMMIT and FinTechEXPO programs within the DXWorldEXPO agenda. Successful transformation requires a laser focus on being data-driven and on using all the tools available that enable transformation if they plan to survive over the long term. A total of 88% of Fortune 500 companies from a generation ago are now out of business. Only 12% still survive. Similar percentages are found throug...
Druva is the global leader in Cloud Data Protection and Management, delivering the industry's first data management-as-a-service solution that aggregates data from endpoints, servers and cloud applications and leverages the public cloud to offer a single pane of glass to enable data protection, governance and intelligence-dramatically increasing the availability and visibility of business critical information, while reducing the risk, cost and complexity of managing and protecting it. Druva's...
BMC has unmatched experience in IT management, supporting 92 of the Forbes Global 100, and earning recognition as an ITSM Gartner Magic Quadrant Leader for five years running. Our solutions offer speed, agility, and efficiency to tackle business challenges in the areas of service management, automation, operations, and the mainframe.