JicarillaWiki   BasicsOfComponentOrientedDesign UserPreferences
 
HelpContents Search Diffs Info Edit Subscribe XML Print View

This wiki is in 'slumber' mode, just like its associated sourceforge project. Edits are disabled, the content is potentially stale and is not maintained. That said, it contains some really useful stuff still. Enjoy!


The Basic Elements Of Good Component-Oriented Design

(slightly edited from a [WWW]post to the PicoContainer mailing list)

I'll give you the answer up front: It is based on PicoContainer. The rest of this e-mail is the how and the why and more random thoughts.

Here's some very basic ideas about component-based design. I've now spent about 10 hours of actual programming with Pico, and its evaluation time...

Basic Elements

Components

A typical application should have very few active components (perhaps a socket server, an event listener and event dispatcher, a command-line listener, a cron-style daemon, perhaps a "really big main(), perhaps some other kind of queuing or command mechanism"). Most components should be passive, only acting in response to the active components utilizing them.

Components are utilized exclusively through work interfaces. All components should be strict IoC components.

Developers are lazy, so it should be easy to create components. Reuse is bliss, so it should be easy to use things that were developed externally as components (and, since developers are lazy, it should also take very little work).

Container

A container is responsible for instantiation of and otherwise managing all components. In particular, this includes dependency management. The container should enforce IoC and the exclusive use of work interfaces. It should otherwise try to stay out of the way.

All instantiation and management "policy" should be trivially but fully customizable (I may need some single-use components, some per-thread components, some singleton components, some pooled components, some remoted components). The same goes for dependency management policy (I may want automatic resolution for the most part, some bits manually resolved, and some things lazily resolved). Furthermore, all this policy must be fully seperate from the components it applies to.

In the case of container failure, I need to know exactly what policy failed. In enterprise stuff, I may want to specify fallback policy, whereas in development, I want to trigger debug mode. Again, this means everything had better be extensible.

In other words: the container should be built using components itself :D

Data

There should be a very clear seperation between components and data objects. Components act upon the data. The container should have nothing to do with creation and/or destruction and/or management of data objects.

There is a special case: component configuration. Components almost always include a minimal amount of state. Furthermore, its very difficult to encapsulate this state into a big "configuration component" without sacrificing the reusability of components in different contexts.

Hence, the container must support a mechanism for component configuration. This mechanism, again, needs to be configurable. Ideally, this mechanism is orthogonal to the handling of other policy (so that I can for example easily switch from xml-based to script-based configuration for single-use components, per-thread components, for remoted and for pooled componentS).

Magic

In general, magic is bad. It reduces predicatibility, adds overhead, reduces portability, adds complexity, adds dependencies, ups the learning curve. It needs to be avoided, when used, minimalized and encapsulated away.

What do I classify as magic? The use of interceptors, reflection, aop, bytecode modification tools, the use of "attributes" or any other kind of metadata. The use of other languages (like xml or beanshell) to escape type safety, or simply using Object as a parameter everywhere coupled with lots of typecasts.

These concepts and PicoContainer

Components

Type 3 components rock. PicoContainer could be a little better in its support for existing third-party materials. That could be done by either providing a big catalog of 'wrapper' components or by adding better support (in nano) for type-1 and type-2 components.

RFC: adapters for type-1 and type-2 components (heck, even type-4 components, ie EJBs) that allow transparent use of these in pico-based applications.

Container

The instantiation and management policy of Pico still leaves a little to be desired. While it is quite easy to set up singleton-style objects and single-use objects, (per-thread seems pretty feasible as well) it is not as easy to support any kind of pooling, basically because no release() semantics exist.

This is a pretty big dillemma. In avalon, there are release semantics, and this allows for pooling to be transparent, at the (pretty big!) cost of requiring all components to always release all dependee components (including the singleton-style ones). I can't figure out how to do clean pooling in a pico-based environment. A release() would be a big sacrifice.

Dependency management policy in Pico boils down to "trust our automatic, lazy, conservative policy, or do it completely manually". I'm not so sure about how to provide better support for less extreme policy without making the code much more complex. As it stands now, the way to replace this is to replace some of the code in the defaults package, and that's sort-of workable.

Pico exception handling is pretty good!

Data

The way pico currently supports configuration is its weak point. Consider this constructor:

 BasicSocketServer( 
   String address, int port, int backlog, int threads ); 

if I use it in other code, It looks like

 new BasicSocketServer( "localhost", 80, 50, 50 ); 

It is just as ugly in many other formats (like xml), its horrendous if you're talking to the default Pico directly (with all those ComponentParameters you need to create).

Paul suggests:

 public class BasicSocketServerConfig 
 { 
   private String address; 
   private int port; 
   private int backlog; 
   private int threads; 
 
   public BasicSocketServerConfig() {} 
 
   public void setAddress( String a ) { address = a; } 
   public void setPort( int p ) { port = p; } 
   public void setBacklog( int b ) { backlog = b; } 
   public void setThreads( int t ) { threads = t; } 
 } 

resulting in

 BasicSocketServerConfig c = new BasicSocketServerConfig(); 
 c.setAddress( "localhost" ); 
 c.setPort( 80 ); 
 c.setBacklog( 50 ); 
 c.setThreads( 50 ); 
 new BasicSocketServer( c ); 

what I don't like about this one is the plethora of data beans I'll have to code. Mike said:

 Properties p = new Properties(); 
 p.setProperty( "address", "localhost" ); 
 p.setProperty( "port", "80" ); 
 p.setProperty( "backlog", 50 ); 
 p.setThreads( "threads", 50 ); 
 new BasicSocketServer( p ); 
 
 BasicSocketServer( 
   Properties p ) 
 { 
   address = p.getProperty( "address" ); 
   port = new Integer( p.getProperty( "port" ) ).intValue(); 
   backlog = new Integer( p.getProperty( "backlog" ) ).intValue(); 
   threads = new Integer( p.getProperty( "threads" ) ).intValue(); 
 } 

which looses me type safety and still looks pretty ugly. Furthermore, I'll usually want to document the keys somewhere, leading to:

 Properties p = new Properties(); 
 p.setProperty( BasicSocketServer.ADDRESS_KEY, "localhost" ); 
 p.setProperty( BasicSocketServer.PORT_KEY, "80" ); 
 p.setProperty( BasicSocketServer.BACKLOG_KEY, 50 ); 
 p.setThreads( BasicSocketServer.THREADS_KEY, 50 ); 

which still leads to a lot of typing (I have to do all those public static final Strings as well). I've also tried using Map (as opposed to Properties) for a while, but that's still ugly.

What _is_ clean? Named parameters! So neat:

 new BasicSocketServer( 
   address = "localhost", 
   port = 80, 
   backlog = 50, 
   threads = 50 ); 

Of course, java doesn't support this. If you're using a scripting language (like Jyton or JRuby), you might be able to do it there (I'm not so sure), but otherwise we're stuck with something more clumsy. Considering all this, perhaps the most elegant still is

 bss = new BasicSocketServer(); 
 bss.setAddress( "localhost" ); 
 bss.setPort( 80 ); 
 bss.setBacklog( 50 ); 
 bss.setThreads( 50 ); 
 bss.initialize(); 

but we're all convinced this is the root cause of all evil! Aargh! Dilemma.

Magic

PicoContainer is nearly magic-free. You can do everything in java, there is very little typecasting. When there is a cast, its relatively safe:

 MyComp comp = (MyComp)pico.getComponentInstance( MyComp.class ); 

the little bit of magic is in the selection of the constructor, the gathering of the dependencies and the final instantiation of the component. The school of magic in use here is reflection, which is a defendable choice. Furthermore, its easily shown that it is unavoidable to introduce some magic here.

This magic is well-isolated and well-documented (in the test cases, that is). PicoContainer is low on magic, which is a good thing.

Conclusion

All that typing, and just a single RFC. That must mean pico is about ready for 1.0! IMHO :D

What about technology X?

Now, I know roughly half of the people who are reading this will think or say "but what about technology X"? Where technology X will often be another component framework, and a lot of time will then be spent pointing out all the advantages and benefits of using technology X, all the features it supports, all the things it can do that PicoContainer does not.

If you're thinking something like that at this point, you've missed the point. I've tried to highlight some of basics here. Technology X most likely adds materials above and beyond those basics. That is cool, and probably many people will be thrilled by the availability of those features. Not me. Why? [BadWikiTag]The more features there are, the more likely it is there will be some that you don't need. But you should feel more than free to disagree, and use Technology X instead of PicoContainer. That'd be way cool as well. Just try and make sure you keep the basic principles in place.

Comments

Please. Point out all the errors and dumb ideas :D. Make sure to look [WWW]here for earlier comments from people smarter than me.


PythonPowered
EditText of this page (last modified 2007-02-18 14:14:22)
FindPage by browsing, title search , text search or an index
Or try one of these actions: AttachFile, LikePages, LocalSiteMap, SpellCheck

Creative Commons License
The contents of this wiki are licensed under a Creative Commons License.