DekGenius.com
Previous Section  < Day Day Up >  Next Section

4.7 Advanced Topics

Now you've seen three tools for achieving transparency. If you're anything like my clients, you're probably wondering which is best. I'm going to carve that decision into three pieces:

  • If I'm building a transparent service myself, I prefer reflection. I'd simply prefer to call a library than build a code generator or byte code injector. I prefer to have business logic within my domain model (instead of just data holders), and that eliminates code generation. Though the performance is doubtlessly superior, byte code generation is too difficult and risky for most small or inexperienced IT shops.

  • If I'm buying a tool or framework, I like the idea of byte code enhancement. I like that you pay much of your performance penalty at build time instead of runtime and I like that after the build, I don't have to worry about the service. With tools like JDO, I've rarely had instances where byte code enhancement made things difficult for me to debug, and I've always been impressed with the flexibility of byte code generation over reflection. As a case in point, after coming down hard on JDO vendors in their marketing literature, Hibernate in fact added a byte code enhancement library, called CGLIB, to improve certain aspects (such as lazy loading).

  • I don't mind code generators, but I don't lean on them for transparency. In general, better techniques get the same benefits without some of the drawbacks mentioned earlier in this chapter.

If you're gung-ho about transparency, keep an eye on a couple of evolving debates. The first is the concept of coarse- and fine-grained services. The second is the future of programming techniques that may enhance your experience.

4.7.1 Coarse- and Fine-Grained Services

Nearly all applications support two types of services: coarse- and fine-grained. You may decide that it makes perfect sense to attach all services to the same point. Be wary, though. Many early EJB applications used that design, God rest their souls. Your problem is two-fold. First, if you present an interface, your users may use it whether it's a good idea or not. Second, different services have different performance requirements.

Consider CORBA for a moment. The idea was to have very large object models, which could find and talk to each other whether they were in the same memory space or across the globe. If you bought into that notion (as I did), you know how damaging it can be. The problem is that interfaces often have fundamentally different requirements. If your user interface wanted to display every field on a distributed object, it would need to make a distributed method call for every field, which is very expensive. Let's take the problem one step further. Let's say that you wanted to display every line of an invoice from across the network. You'd have to make a call to every field of every object on line item on an invoice, as in Figure 4-8. Each call represents a round-trip across the vast network, and regardless of how efficient your code is, the speed of light is still immutable. You have to be intelligent about the way that you apply transparency.

Figure 4-8. CORBA failed because it treated every service as a fine-grained service
figs/bflJ_0408.gif


Instead, you need coarse- and fine-grained interfaces. Your model provides your fine-grained interface, and a façade provides a coarse-grained interface. Think of a fine-grained interface as private. You only want to share the most intimate details of an object to a selected number of, ahem, clients. Your public façade will provide the entry point to the rest of the world.

You probably code this way already. If you don't, you're in for a treat. Facades make a convenient interface for providing a secure, transactional, or distributed service. You can offer these services transparently with many of the techniques in this book. Your façade need not be a session bean. You can achieve many of the benefits through lightweight containers and possibly RMI. The difference between this model and CORBA is striking: you don't sacrifice transparency, but you can attach coarse-grained or fine-grained services to the appropriate interfaces. Apply coarse services like messaging, distribution, transactions, and security to your façade, and your fine-grained services—such as logging and persistence—to your model.

4.7.2 A New Programming Paradigm

You might have noticed that object-oriented technologies do not handle services, like security or logging, that broadly reach across many objects very well. Academics call this problem crosscutting concerns. For this reason, many researchers and leading edge developers increasingly tout the aspect-oriented programming (AOP) model. While it's still in its infancy, AOP lets you insulate the issues of crosscutting concerns from the rest of your application. I'll talk more about AOP in Chapter 11.

It's my belief that new programming models evolve much more slowly than predicted. I also believe that once they succeed, they have a much bigger impact than we expect. Such was the case with object-oriented technology, which grew incrementally over 10 years through the adoption of C++, the commercial failure of Smalltalk, and finally the successful adoption of Java. You can find similar adoption patterns around high-level languages, structured programming, and even interpreted languages. While you might not see widespread AOP adoption by next year, you will likely see ideas that support an AOP move to the forefront rapidly:


Transparency

In this chapter, you've seen the impact of transparency across the Java language. The fundamental goal of AOP is to take crosscutting concerns out of your model.


Byte code enhancement

Many developers and decision makers reacted violently to any framework considering this technology, especially early versions of JDO. Increasingly, Java developers are recognizing the value of byte code enhancement. With each new implementation, support gets stronger.


Interceptors

Aspect-oriented frameworks intercept program control at critical places, such as when control passes into or from a method, when objects are destroyed, and when variable values change. Interceptors provide a convenient way of attaching behavior to an object through configuration, without forcing changes upon a model.


Lightweight containers

In Chapter 8, you'll see a lightweight container called Spring in action. Designers quickly saw that containers such as Spring, Avalon, and Pico make AOP easier.

Networking in person or online is the best way to deal with constant change. You need to be near the buzz so that you can respond to the ceaseless waves of changes as they break.

    Previous Section  < Day Day Up >  Next Section