On Thu, Feb 14, 2013 at 04:24:48PM -0800, Frank Zhang wrote: > 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. > >
+1 to what Frank is saying. Runtime configuration is much more flexible than compile-time scenarios! -chip