views:

239

answers:

4

Before I ask my "general" question, I wanted to present some quotes to my high-level general understanding of the business delegate pattern:

"You want to hide clients from the complexity of remote communication with business service components."

"You want to access the business-tier components from your presentation-tier components and clients, such as devices, web services, and rich clients."

Lets say you have large J2EE web application. When I mean large, I mean that the application has been developed for several years and by many different people and departments. The system wasn't designed well for growth. Right now, lets say the application is configured with one web application.

It would have been great if the application were more modular. But it isn't. One piece of code or library can bring down the entire system. Testing and other means are used to prevent this, but ideally this is just one monolithic web application.

Here is my question; how do you normally avoid this type of design with J2EE apps, where the application grows and grows and one separate application can bring down everything.

I am not familiar EJBs and don't plan on using them for anything too serious. But, the concept of the Business Delegate and Service Locator Pattern seems like a good fit.

Lets say you have a shopping cart screen (same web app) and a set of screens for managing a user account (same web app). In your web-tier (some kind of MVC action method), it seems you could have a Locator that will get the business specific interface, invoke those interfaces per module and if something goes wrong with that module then it doesn't kill other code. Lets say the shopping cart module fails (for whatever reason), the user account screen still works.


+1  A: 

In a healthy software development environment, the application "grows and grows" because bussiness people ask for changes and new features and usually there is nothing wrong with it.

Let's forget about the scalability problem, and focus in the design problem, with leads to a very painful maintenance.

What you need to do is separate your application in modules that makes sense to the business guys (and the users). Each module of your system should have a clear business mean that reflects the application domain.

razenha
+1  A: 

ALl of those ideas are fine, and would be perfectly reasonable if you were starting from scratch. Unfortunately, you're not starting from scratch but dealing with a prototypical Big Ball of Mud. Believe me when I say that I feel your pain.

More important than the specific pattern is to impose some sort of order, any sort of order, on this mess. More important than your specific design choice - can you reaonably impose your design choice on the entire system so that there's a single unifying paradigm that carries through the whole application?

If your design satisfies the design requirements and conceptually simplifies the application then it's valid.

Steve B.
+1  A: 

The best way to improve a system like this is to slowly make it better. If your system is anything like the systems I've worked on, changing the code often leads to bugs. Automated tests are a way to reduce the chance of introducing new bugs, but often the code wasn't written with testing in mind, and changing the code to make it easier to write tests can lead to bugs.

The way around this problem is to introduce some automated integration tests, and use those tests as a safety net as you carefully refactor the code and introduce tests at a lower level. Making code more testable often results in introducing interfaces and abstractions that make the code easier to work with. It also often requires separating business logic from presentation logic (since testing both together is painful) and breaking out our code into modules (since classes with many dependencies can be hard to test).

When you write new code for your system, try to write unit tests while you write the code. This is much easier (and therefore less frustrating) than writing tests for legacy code, and gives you a chance to see where you might go when you refactor your legacy code.

I know of two excellent bugs on this subject: Working Effectively with Legacy Code by Robert C. Martin and Refactoring to Patterns by by Joshua Kerievsky.

Finally, consider using a dependency injection framework, like Spring or Guice. Dependency injection makes it easier to make your code testable with unit tests. It also makes it easier to follow good design practices like the Dependency Inversion Principle and the Interface Segregation Principle.

NamshubWriter
+1  A: 

The best way to avoid such a mess when you were given a chance to restart is:

  • Use the Spring Framework throughout.
  • Pay attention to high-cohesion, low coupling: make sure there are no circular dependencies between package (com.myapp.packageA depends on com.myapp.packageB which depends on com.myapp.packageA). There are some great free tools like Architecture Rules that can verify that for you automatically.

With these two rules you'll already be forced to follow sound good design principles. Otherwise, design needs constant attention. The point of any design effort is to reduce uncertainty, so you basically have to know why you're designing in the first place.

Steven Devijver