Service Oriented Architecture Antipatterns
- Posted in:
- SOA
- Architecture
Was just browsing around today and stumbled upon this article on IBM.
Good reading if you are into SOA.
Was just browsing around today and stumbled upon this article on IBM.
Good reading if you are into SOA.
I work in an intranet team that develop customized solution for my current company, its parent company and its subsidiaries. Needless to say, most of the time we found that we need similar domain objects such as Projects, Tenders, Contracts, Users / Employees, etc. across multiple application development projects. Of course, one thing that comes to mind is "Hmm... it would be great if we can pull all of these common domain objects from a single source to avoid duplication."
But... wait, it's not as simple as that.
Each application might not be used across all of the intranets. For example, application 1 is being built for subsidiary A, application 2 is being built for subsidiary B. The companies sometime are not even in the same country.
The easy way out: why the heck bother with a single source, just let each application has its own domain objects, even if it is similar in nature (application 1 has its own project domain, application 2 has its own project domain, etc.). Completely independent of each other. Nothing wrong with that, right?
Until... subsidiary B has a chance to look at the ...say... Leave Request application that is being used at subsidiary A and decided they want to use it too, but with some modifications to fit its own requirements. *Smack head* DOH... now what... well, again going with the simplest solution / hack that comes to mind... let's separate the database, tweak the application a bit, save it as LeaveRequestSubsidaryB, and there you have it. Nothing wrong with that, right?
Until... parent company (enterprise level) decided that all of these data should be integrated to make such and such big report / KPI on employee attendance or blah blah blah. You get the idea... Now what? *Scratch head* Uhm... create a common data container for all the different LeaveRequestXXX application, extract data from each of these apps and produce report on the common data? Well, that's one way to go. I am sure there are others.
The point of this long winding rambling is, well, this common data thing is bugging me. It keeps popping up no matter what. Why don't we just create one that can be shared across the enterprise? But, do we even have the time to do this first? We will certainly have to take into account all of the complexities of requirements from different applications and design it appropriately. That takes time. A LOT OF TIME.
Meanwhile, management keep asking when is application A going to be completed? What about application B, and so on... push push push ***ARRGHH! head is about to explode***
How can we move along different projects without having to wait for this "common domain object library" to be finished first?
Well... I gave this some thought and this is far from perfect, but here they are anyhow:
Well, playing around with the idea, I managed to build a working prototype of point 1 and 2 so far. The hard part is designing the real interfaces. What are going to be the abstracted methods for such interfaces? I am starting with the simplest stuffs for now, for example, getting a list of Project to populate a dropdown list / lookup. That should be common enough across multiple application. There will be other more specific methods, but enough for now.
So, what do you think? Is such thing achievable? Or should we just give up on it and go w/ separate app for separate subsidiary, and reconsolidate the data when necessary?
What's the best practice on interface placement?
I was playing around with this idea after seeing an episode of DNRTV and thought it might be nice to just put this up in the blog and ask others' opinions on this subject.
For now, I can only think of 3 possible options for this issue. And they are as follow:
Option 1.
Where: Place them in the assembly where the interface is implemented
When:
Some possible motives:
Example: I have an ILogWriter that is being used internally and my application configuration has a section in it where I can choose which kind of logging mechanism to use.
//Assembly : Foo.exe //File : ILogWriter.cs namespace Foo { public interface ILogWriter { void Write(string text); } }
//Assembly : Foo.exe //File : ConsoleLogWriter namespace Foo { public ConsoleLogWriter : ILogWriter { public void Write(string text) { Console.WriteLine(text); } } }
//Assembly : Foo.exe //File : FileLogWriter using System.IO; namespace Foo { public FileLogWriter : ILogWriter { public void Write(string text) { //append text to file here } } }
//Assembly : Foo.exe //File : Class1.cs using System; using System.Configuration; namespace Foo { public Class1 { public void Main(string[] args) { // Do something ILogWriter logWriter = (ILogWriter) Activator.CreateInstance(Type.GetType(ConfigurationSettings.AppSettings["LogWriter"])); } } }
<!-- File : app.config --> <appSettings> <add value="Foo.ConsoleLogWriter, Foo" key="LogWriter" /> </appSettings>
Option 2.
Where: Place them in the assembly where the interface is being used
When:
Some possible motives :
Example: I have an IViewUserView in my presentation layer assembly and my actual view implementation will reference the presentation layer assembly since its going to use it anyway.
//Assembly : Blah.Presenter.dll //File : IViewUserView.cs namespace Blah.Presenter { public interface IViewUserView { int UserID { get; } string Login { set; } string Password { set; } // More here ... } }
//Assembly : Blah.Presenter.dll //File : ViewUserPresenter.cs using Blah.DTO; using Blah.Task; namespace Blah.Presenter { public class ViewUserPresenter { private IViewUserView view; private IUserTask task; public ViewUserPresenter(IViewUserView view) : this(view, new UserTask()); public ViewUserPresenter(IViewUserView view, IUserTask task) { this.view = view; this.task = task; } public DisplayUser() { IUserDTO userDTO = task.GetUserById(view.UserId); view.Login = userDTO.Login; view.Password = userDTO.Password; // More here ... } } }
Option 3.
Where: Place them in their own assembly (assembly of just interfaces)
When: You should use this one when the interface is used by more than one assembly
Some posible motives :
Example: I have an IUserDTO (Data Transfer Object) that is being used by 2 other assemblies (Blah.Task and Blah.Presenter). Then it makes sense to put it into another interface specific assembly (Blah.Core).
//Assembly : Blah.Core.dll //File : IUserDTO.cs namespace Blah.DTO { public interface IUserDTO { string Login { get; set; } string Password { get; set; } // More here ... } }
//Assembly : Blah.Core.dll //File : IUserTask.cs namespace Blah.Task { public interface IUserTask { bool Login(IUserDTO userDTO); // More here ... } }
//Assembly : Blah.Core.dll //File : IViewUserView.cs namespace Blah.View { public interface IViewUserView { int UserID { get; } string Login { set; } string Password { set; } // More here ... } }
//Assembly : Blah.Task.dll //File : SecurityTask.cs //Reference: Blah.Core.dll for the IUserDTO interface // ... using Blah.DTO; using Blah.Task; using Blah.DataAccess; namespace Blah.Task { public class SecurityTask : ISecurityTask { public bool Login(IUserDTO userDTO) { return SecurityDataAccess.Instance.Login(userDTO.Login, userDTO.Password); } } }
//Assembly : Blah.Presenter.dll //File : ViewUserPresenter.cs //Reference: Blah.Core.dll for the IUserDTO, IViewUserView and IUserTask interfaces // ... using Blah.DTO; using Blah.Task; using Blah.View; namespace Blah.Presenter { public class ViewUserPresenter { private IViewUserView view; private IUserTask task; public ViewUserPresenter(IViewUserView view) : this(view, new UserTask()); public ViewUserPresenter(IViewUserView view, IUserTask task) { this.view = view; this.task = task; } public DisplayUser() { IUserDTO userDTO = task.GetUserById(view.UserId); view.Login = userDTO.Login; view.Password = userDTO.Password; // More here ... } } }
These examples and options are just what were on my mind when I wrote this post and not to be taken as a real guideline for interface placing. If anyone should know a better way to do this, by all mean, please share them.