Thursday, December 4, 2008

Be a good investigator

We use a machII framework around our application. We also use coldSpring to manage the relationships and instantiation of collaborating components in our domain.

A quick review, for my own brain too. Machii helps to organize large scale enterprise level applications and promotes OO design of the application, or at least promotes MVC design pattern. There is no denying that, Machii forces the separation of concerns between the presentation, control and (model)domain layers of the application. It also promotes OO design by using listeners, that do the requesting of data from the domain. It is possible to use Machii and listeners and still be using prodedural programming techniques, guity. Moving on.

The application in question consumes lots of complex data that is served up by the domain via services. This is in line with SOA type architecture. Services oriented architecture. The domain makes available services that the machii application listeners know about. The listeners have knowledge of services and can speak to them. The application does NOT KNOW ANYTHING about the domain or model layer that is providing or peristing the data that it needs.

Picture machii doing its job, housing the views and the events and the listeners, that know about services that speak to the data model layer. Whenever something happens in the application, an event is fired, the event has *commands that are part of it - like requests for data and calls to other listener funtions. The arguments or data provided during the event is passed along via the event to the listener who hands that off to a service. The service knows then what to do with it. Recall that the service HAS knowledge of who it is serving. The SOA architecture promotes the notion of the service as the SOCIAL beast in the equation. The service will have much of the bus. rules or logic contained within it. It does a lot of the heavy lifting or thinking for the other components in the domain. The service knows what do do in this situation or that situation, when this piece of data is missing or if a specific type of data is encountered.
Recall that a service probably has its own set of dependent components that must exist for it to do its job. A common occurance is a DAO or Gateway or persistence bean that the service relies on to do its job. If any of these other collaborating components does not exist, the service fails.
The SERVICES, being social, often need to know about other services, not about the other services collaborating entities, just the service itself. This need to know about each other had much to do with the birthing of ColdSpring. With, as the name implies, follows the concept of Spring in the Java world, which is a framwork that helps manage the complex relationships that exist between the collaborating entities in the domain.

ColdSpring "lifts" the knowledge of the collaborating entities out of the entities themselves and places them into a separate container. This is abstraction at its finest.

Tradoffs - there is always tradoffs when you use a framework, like machii or coldSpring. In the case of coldSpring, that is a slight performance overhead and the need to maintain a separate XML style document. A little complexity at first. The gain is a one stop place to create and manage the relationships that exist between your services, DOAs, Gateways.

We have two separate coldSpring xml files, one that is used by the application and another than is used by a sub- application. When i built the sub app, i originally had the domain components instantiating their own collaborating components, this is the natural way to build the app, not seeing the need for a framework initially, who needs it! Eventually, as the sub app grew in complexity and collaborating entities, the need became more clear. I created a new *bean building xml file (this is the container that holds all the bean definitions). The coldSpring configuration file consistes of bean definitions complete with references to dependent components. CS calls this dependency injection -this is usually reserved for those social services, who need to have their dependent DAOs and gateways and other services to work properly.

The problem

In my sub - app coldspring file, i named a bean the same as one that already existed in the root coldSpring config. file. Even though i pathed the bean in the sub app to a different component, it seemed to ignore the bean def. Seems if a beanname already exists in the current scope, it will not read the next. It could be a problem with how i am using the scope? -

The symptom

The problem reported as a failure to set an injection statement in # 2

1 - model.questions.QuestionService.cfc
2 - assessments.questions.QuestionService.cfc

The Diagnosis

I tried to path # 2 a little different, since I did not want to change the name of the service (this would require me to update the name in a couple other places), but was not successful.
The config file in the sub app was pathed to # 2 but when it tried to do its injection of a DAO, it was reporting the failure in relation to # 1.

The Test

I changed the name of the component in # 2 and updated that name in the appropriate places, a listener, another reference in the CS config file and a reference in another service that was using this and walla - problem gone, lesson learned.

Recall that when you are doing dependency injection in a bean definition in the CS config file, you need an equivently named funtion in the collaborating (injecting) component, with the letters set in from of it. In other words, if you have a service bean being in jected with a DAO, then the injecting DAO must have a setDAO funtion that allows the setting.

Like this - here is the bean defintion *minus the brackets that the blogger does not like

bean id="AssessmentQuestionService" class="assessments.model.QuestionService"
property name="QuestionDAO"
ref bean="QuestionDAO"
property
bean

Here is the function in the service that is being injected

cffunction name="setQuestionDAO" access="public" returntype="void"
cfargument name="QuestionDAO" type="assessments.model.QuestionDAO" required="Yes"
cfset variables.QuestionDAO = arguments.QuestionDAO
cffunction

This is a little intimedating at first, but trust the technology and the beauty of the design. It becomes more clear as to its power and purpose over time, when you add more things to the application and more relationships between collaborating entities.

No comments: