28 June 2007 - 2:44When to use business-logic aspects?

I was reading this post on infoq about applying AOP for implementing business logic transparently. It was a pretty good example (actually the author displayed a very interesting way of consolidating a series of different business concerns into a general advice using a Map of Command objects), but what caught my attention was a comment at the end of the post:
It always surprises me to see how much code people actually place within the AOP advice creating an architectural dependency on AOP that makes it impossible to reuse in another context such as an explicit programmatic interface. I personally prefer to use AOP (or interceptors) as bridges or adaptors from one domain/layer/tier to another domain/layer/tier. I normally start with creating the underlying system divorced of AOP concerns and then add AOP into the mix to alleviate the coding effort and simplifying the programming model for typical extension use cases. I always ensure that it is possible to use an particular feature without the presence of a particular framework or instrumentation runtime.

The reader had a pretty good point: you can use decorators* for implementing this business logic. So when would you use AOP? I would use for implementing business logic concerns if they are cross-cutting concerns, if they apply widely across the code-base. In the above example the advice was a notification module that was sending an email when the user was registering. If you would have needed to send a notification when the user was purchasing an item, when an item was shipped to the user, etc… you would have a cross-cutting concern (a business logic concern) that needs to be applied transparently to the application. Another example when I would use AOP is for transient concerns, for concerns that should not modify the code base but that need to be implemented.
Business logic advices come with management costs (you have a piece of business logic detached from your code-base, you have to manage that). Implementing interceptors thru decorators come with coding costs (you usually need to create a new class). One should look at these costs and determine which approach is more cost-effective. As always, use AOP only for binding components together, the business logic advice should contain no business logic at all, but simply logic for binding a business logic bean (the notification module in the above example) to a different bean. I am not sure if the example followed this approach, though.

* AOP can be thought of as decoratoring unleashed, an advice applied to a class is a decorator.

No Comments | Tags: AOP, Econo-computing

27 June 2007 - 0:40Un citat frumos

O ultimă amintire: sîntem în centru, la o terasă de pe lîngă Inter, bem bere la halbă, eu am vreo 22 de ani, el vreo 28 şi plănuim să mergem undeva în munţi. Sîntem ex­trem de serioşi, stabilim traseul (mai era şi un al treilea

cu noi, nu mai ştiu cine), logistica, deşi ştiu prea bine__

şi ştie şi el probabil — că noi doi n-o să plecăm nicioda­tă împreună undeva, că sîntem total incompatibili, că eu voi fi mereu complexat de inteligenţa şi forţa lui, iar el plictisit de veşnicele mele tăceri. Dar stăm cu capetele aplecate asupra unei hărţi, şi deasupra noastră fîlfîie în vînt copertina de la Societe Generale, şi e un soare puter­nic de primăvară, şi noi sîntem încă foarte tineri.

“Marele Mircea” de Mircea Cartarescu.

No Comments | Tags: Personal

21 June 2007 - 17:54Le fin d’un blogue

Une des blogues les plus connus dans le 514 vient de s’éteindre. C’est dommage, il etait un de mes favorits.

No Comments | Tags: Personal

21 June 2007 - 0:29REST and WS - part 4 (or when REST turns ideological)

I was reading this post about writing complex applications REST-style and all seemed pretty well till I came across this business logic method wrapped up as a DELETE HTTP method:

/{acct_id}/open_orders/{order_id} DELETE orders delete cancelOrder

Mapping a CRUD method to a business method is a pretty bad thing, if anything the service which gets exposed REST-style should have very clear URL-to-business method mappings. It is pretty bad when you advertise one thing and when you do another. Using CRUD methods masquerading as business methods is pushing round pegs into square holes, if anything it obfuscates the contract that the REST-talking application has with the outside world.
Another bad thing with using CRUD methods for implementing business logic operations is that it seems that you run out of options due to the poverty of the REST syntax coming from the limited number of HTTP operations that it maps to. From what I see you can only do 4 methods on an order GET,POST,PUT and DELETE. What should I do if I want to partially commit my order (send my order to a another trader that will fulfill it)? DELETE is taken, it cancels an order, what other method in the HTTP protocol should I use REST-style in order to signal the server that I need to partially commit an order?
REST is pretty limited as far as I see it and I see it fit only for CRUD methods. You can tout all over the place that it scales to Internet-size but fact is 4 CRUD operations do not scale to complex interactions. You can do pretty much everything using those 4 operations by twisting your domain to fit your impoverished environment, but you can do the same thing in COBOL, Fortran, etc…

Later edit: You could have probably implement the cancel order method REST-style by creating a new URL on which you would cancel an order thru a PUT operation like below:

/{acct_id}/cancel_orders/{order_id} PUT orders create cancelOrder

But the problem still remains: you are trying to express a business contract using CRUD methods. Pushing round pegs into square holes…

Later edit:  When you remote an application the contract that this application exposes should be crystal clear. Having CRUD operations masquerade as business logic operations obfuscates this contract.

No Comments | Tags: Development

20 June 2007 - 14:11Econo-computing

It looks like there are other people trying to use economic concepts for describing software development. Pretty cool…

No Comments | Tags: Econo-computing

19 June 2007 - 23:29Transparent development - one example

A while ago I wrote about transparent development - a way to develop software that implements new business logic in a code base while making minimal, if any, changes to the existing code. I wrote about this primarily because I am working with legacy systems and making a change in this systems usually carry a pretty big cost. As a side note, a while ago I also wrote about the lack of literature in dealing with legacy systems. Design patterns for wokring on a legacy application anyone?

Anyway, my previous post was pretty theoretical, if anything, so I decided to provide an example of transparent development. My intention is to identify best practices that allow a developer to implement a new piece of business logic while making very small changes to the original code.
So this is the first post in this category (I hope more will follow). The example that I want to give is the following:
Suppose that you have a sequence of steps that is being widely used and that you need to modify this sequence only for a very small concern, how would you go about it. This is the example:
You have class AbstractTaxService that among other things implements the method prepareTradeForTax. This method is the sequence that I was talking about:
public class AbstractTaxService{

public method prepareTradeForTax(Trade trade){

initTaxService()
initTradeForTax()
enrichTrade(trade)
transformTradeToTaxFormat() // this will transform the trade in a format that the tax service understands

}

}
AbstractTaxService has 3 sub-classes that use the method prepareTradeForTax and which expand on it: CommodityTaxService which taxes commodity trades, EquityTaxService which taxes equity trades and FITaxService which taxes fixed income trades. Each one uses the prepareTradeForTax method as below:
public class CommodityTaxService{

public method prepareForTax(Trade trade){

super.prepareForTax(trade); // call the method in the super class
notifyCommodityTradeSource(trade); // will notify the source of the commodity trade that a trade is about to get taxed

}

}
public class EquityTaxService{

public method prepareForTax(Trade trade){

super.prepareForTax(trade); // call the method in the super class
notifyEquityTradeSource(trade); // will notify the source of the equity trade that a trade is about to get taxed

}

}
public class FITaxService{

// doesn`t override the method

}
All is well, the system has been running for a few months when this requirement comes in:
The FITaxService needs to call a  new method enrichFITrade before transformTradeToTaxFormat and after enrichTrade for a particular trade type. Oops. The sequence gets broken. The ugliest fix would be to copy and paste AbstractTaxService prepareForTax in FITaxService. Another fix would be to touch-up the original AbstractTaxService prepareForTax so that it calls only initTaxService and initTradeForTax and then change CommodityTaxService, EquityTaxService and FITaxService so that they will call the method transformTradeToTaxFormat in their versions of prepareForTax. But this is ugly, it requires massive changes and massive regression testing.

You would like to change nothing in the above configuration and yet somehow implement this new sequence in FITaxService. One transparent implementation would be the following:
Sub-class AbstractTaxService with FlexibleAbstractTaxService, a class that implements a flexible sequence of steps for preparing the tax trade. Have FITaxService extend FlexibleAbstractTaxService and use it in order to implement the new sequence of steps:
public class FlexibleAbstractTaxService extends AbstractTaxService{

protected String[] taxPrepareSequence = null;
public prepareForTax(Trade trade){

if(taxPrepareSequence == null)
super.prepareForTax(trade)
else
for(int i = 0; i < taxPrepareSequence.length; i++){

// go thru the sequence and execute methods using reflection

}

}

}
The new FITaxService is re-coded as follows:
public class FITaxService extends FlexibleAbstractTaxService {

public prepareForTax(Trade trade){
if(trade.isSpecial()){

// prepare the sequence for handling this special trade

taxPrepareSequence = new String[]{`initTaxService`, `initTradeForTax`, `enrichTrade`, `enrichFITrade`, `transformTradeToTaxFormat`};

 }

super.prepareForTax();

}

}

This way not much has been changed and the new requirement has been implemented transparently.

Some caveats about using this method: it is pretty expensive since it creates a new class, a pretty expensive operation. It would be a good thing if this new class would be flexible enough to cover future requirements, if anything it should be built with this in mind. Also, care should be taken, since this approach creates new classes it could be considered prone to class mushrooming.
The cost of this approach (creating a new class) should outweight the costs of other methods (building up a battery of regression tests in order to determine if the changes in multiple classes have not had a bad effect on their functionality) if this approach is to be taken.

P.S. Lately I have started to look at sub-classes as though they ar decorators which you can use in order to implement behavior while minimizing the changes done to a code-base. These decorators carry a cost (sub-classing which requires a new class) that should be minimized.

 

No Comments | Tags: Development

1 June 2007 - 14:26REST and WS - part 3

I was reading this article on infoq about REST winning in front of WS. Rather than REST gaining ground I see this as a split in software development environments. The fact that Amazon, eBay, etc… are using REST doesn’t validate REST as a technology, it simply opens up Amazon’s IT infrastructure to a group of people that cannot/don’t want to use WS. This group of people is made up of PHP coders, PERL hackers, possibly Ruby and Python developers. This group of people doesn’t use WS, they are not even present in the WS specification process, they tend to ignore it. I am not sure about the reasons for this attitude, it has to do a bit with lack of resources and a decentralized decision making environment (I am not sure that the PHP or Python community can be a part of the WS process, these communities are usually not part of standard bodies *), a bit with the fact that the apps they are working on don`t need WS capabilities (I`d be surprised if your typical PHP bulletin board needs transparent security certificates exchange or long-running transactions) and probably a bit more with ideology. REST is remoting for small, LAMP, webby applications, WS is remoting for enterprise applications and their differences are the result of different needs and resources dedicated to these needs rather than some fundamental difference in architetural styles.
So rather than seeing this shift in REST and WS usage as a validation or invalidation of one style or another I see it as as split in the development environments. WS will very likely be confined to JEE and C#, basically it will be used for enterprise development and communication within this environment. REST will be used for deployments facing heterogeneous clients since REST is adopted and accepted by pretty much all the hackers/coders out there (if a PHP guy can agree with a Python guy on something is that REST is good and WS is bad).
So applications will be remoted differently based on the client to which you are exposing your application. If this split will do anything it will make the remoting of an application a process de-coupled from the application itself and coupled more to the remoting environment (REST/WS/RMI, etc…).

Remoting an application should be thought from now on as a transparent process which should be applied to an application transparently. This should have been done anyway, but the REST/WS split probably brings the point home a lot harder.

P.S. There is a big architectural difference between REST and WS, namely REST deals mostly with exposing state and its associated operations (CRUD) while WS deals mostly with exposing business logic. If I am correct REST can be thought of as a way to remote the data-layer, while WS as a way to remote the business logic. With REST the business logic layer is to developed on the client side, while WS gives it up-front. I think this is a pretty serious limitation of REST, the fact that you have to re-code the business logic in different environments is an effort which is not to be underestimated. But with REST you have control over your business logic and the possibilities for mashing up a different client are greatly enhanced.
WS can also remote the data layer, it would treat the data layer as another business concern that has to be exposed, so in this respect WS is more powerful than REST (it can implement REST-specific functionality if it wants to).
Again, the split between REST and WS is a split in development environments due to various market forces playing out in the IT landscape and not a debate about the efficiency of one style vs the other.

* I wonder if the famous get method of the REST architecture is symbolic of the relationships in these communities, it appears as though the Perl/PHP/Python communities can agree only on the lowest-common denominator. How more common and generic can you get than get?

1 Comment | Tags: Development