I have said too much about XML files recently, excuse me for raising this topic 
again, 
I really want to elaborate why text (e.g XML) configuration files is so 
important and how 
it decouples your project especially for project written by static language 
like java.

Let me cite our new ApiDiscoveryService as an example(This service is very 
good, I use it
as example just because I encounter a small problem and the problem is a good 
study case
for decoupling code using text configuration files).

The problem is: ApiDiscoveryService discovers API commands by invoking 
PluggableService. getCommands().
Each plugin service needs to implement getCommands() which returns a 
List<Class<?>> including classes of
API command the plugin service supports. This is good, lots of project use 
similar way in plugin system.

ManagementServerImpl is a special API service, it registers all orchestration 
API commands like *addHost*. Now
I have a special API called *addBaremetalHost* which inherits *addHost* adding 
one more field.  *addBaremetalHost*
is actually handled by the same orchestration code as *addHost*(but different 
HostDiscover which is another story),
unfortunately, this API belongs to my Baremetal plugin that means I can't add 
it into  ManagementServerImpl. getCommands()
because orchestration code should not have a dependency to plugin code.

The solution is simple, I use a BaremetalManager to register *addBaremetalHost* 
and inject/call orchestration code to deal with it.

However, this case shows us how compiling time dependency in static language 
makes your code tight coupling. 
Everybody programing in java/C/C++ knows the pain of planning your project 
skeleton to avoid circular dependency. 
One of solutions is to use text configuration file. Back to our example, 
ApiDiscoveryService, we can put a folder which
stores API configuration XML at a well-known place, every PluggableService has 
a XML file describing its API and Spring bean
name in the folder. for example:

<apiService>
        <api>
                <command> 
com.cloud.baremetal.manager.AddBaremetalHostCmd</command>
                <acl>some acl</acl>
                <owner>Spring_bean_name_of_baremetal_manager</owner>
        </api>          
<apiService>

When ApiDiscoveryService starts, it scans the folder and parses XML files to 
discover every api/theirs properties/owner bean. By doing this, 
ApiDiscoveryService/
PluggableService/API command classes totally have no compiling time dependency, 
they can freely seat in any packages as long as these packages present in
classpath during runtime. To my case, I don't have to inject orchestration code 
in my plugin anymore,  I just use a XML file to tell ApiDiscoveryService that 
addBaremetalHost
is taken cared by ManagementServerImpl as well though ManagementServerImpl has 
no knowledge about it.

CloudStack used to have similar idea command.properties, unfortunately it's 
only used as ACL declaration now.

This is a trivial example,  but it reflects a truth that compiling dependency 
is naturally making your code tight. Many people criticize dynamic language is 
error-prone because it
lacks compiling time check, but as another side of coin, it's also easy to 
produce loose-coupling code. Thinking about OpenStack, if you were going to use 
Java to fork it, I am pretty
sure the compiling time dependency will drive you crazy.  For instance, 
java-nova and java-cinder both need to know Volume that represents vm disk, now 
where do you define it? in java-nova?
in java-cinder? Then who depends on who? Or totally don't define any data 
structure, using a HashMap to transmit primitive variables, then where is 
beauty of compiling check?

As we have adopted Spring that uses XML a lot in CloudStack, I suggest us 
taking more consideration of text configuration file when designing a new 
feature. it really works.

Reply via email to