It was about a week ago when the patient presented with a problem. “Dr”. he said: “my WCF service hurts really badly lately – especially when I do this”. He lifted his service up to show me. “Ouuuch.”
“Hmm” I replied, “has your service been properly adhering to the tenets of SOA and washing behind his endpoints regularly? It’s important for growth you know.”
“Well,” the patient sulked a little… “its bindings endpoints and are spanky clean. They’re practically brand new, but I have to confess that I haven’t been paying much attention to the tenets of SOA. I know all about them, explicitness, autonomy, schema and contract over class implementation, policy rules yada yada yada. But I really didn’t care about all that when I started. And honestly I still don’t.” I gasped.
Seeing me react, the patient became more determined to finish and talked faster and louder. “Those things just didn’t seem important in my case. Honestly, I really don’t think they apply to me. I don’t plan on showing other people my services. I’m not into that kind of thing. I know other people are, but I only care about being able to cross process boundaries.” With my forehead wrinkled I crossed my arms ready with a barrage of questions.
“I though you were building a web application.”
“I am” he said.
“Then why do you need to cross process boundaries?” I was puzzled.
“Well, you see, sometimes the web app will be deployed in a DMZ where firewall ports have been opened to connect to a database, and sometimes the web app will be deployed in an environment where only port 80 is open.”
I grimmaced and thought to myself. There’s a bigger disease here. “Well,” I said “requirements are requirements”. The patient continued:
“I am using ActiveRecord for this project in conjunction with code generation. I’m generating all of my classes with this in mind. I’d like to set the architecture up so that the user interface uses a factory of sorts to either give me references to my persistent objects in process or give me references to service proxies based on some application configuration settings. Of course I would always handle the object references via their corresponding interfaces so the user interface code isn’t concerned with the implementation details of whether it has a reference to a service proxy or a real in-process object from my domain model. The plan is to create a service for each persistent object, you know, mark up each persistent class with ServiceContract attributes. The trouble is, that when I generate my WCF service proxies based on my persistent objects they look really ugly. Not only are they ugly, but the persistent objects combine state as well as behavior, and without the state, the behavior doesn’t work. Some members do calculations depending on the state of other members. Then of course there’s the CRUD (Save Update Delete etc) members. I know its frowned upon, but I’m strongly considering making DTO classes strictly to use as data contracts to pass to the CRUD members.” “Man, just talking about it makes my service hurt again!”
“Allright,” I said. I think I see what’s going on. “The problem is that you’re an object biggot.” “I thought that was a good thing!” he cried out. “Well, normally I think it is, admittedly I am too, but, now that you’ve got a service involved, things are different. You’re trying to treat your objects as services and what you’ve got to accept is that they’re just not the same. Unfortunately that will always be painful.” I got out my prescription pad and quickly scribbled down my recommendation. I handed my patient the small square piece of paper. Excitedly he examined it to see what the remedy was. “That should get you where you want” I said confidently.
“Remoting!” he exclaimed. “Oh no..” he shook his head looking down at the floor. “That just won’t do.” “What you don’t know, Dr., is that I’ve alredy asked several people. I’ve already talked to three other doctors and ALL of them said ‘never under any circumstances ever ever use Remoting.”
I didn’t say it out loud but I thought to myself “aha, he’s been seeing those WCF biggot quacks.”
“Listen,” I said, “they want you to use WCF because they want you to use real bonafide services. They want your services to grow up to be strong and healthy SOA tenet adherent services. All of that is fine, but you’re an object biggot, you don’t really want to use services and you probably never will. You’ll never change. Trust me, you want remote objects. if you take the perscription I gave you, you can use your objects remotely, across process boundaries the same way you would use them in process. Depending on your performance requirements, I think it should work out just fine, and your UI layer will never know the difference. In the morning the pain will be gone and you’ll feel right as rain. Although, you might wonder why you didn’t come talk to me sooner.”
There was a long pause. I could tell he was thinking.
“Unless…” I said. “you’re willing to go through a little surgery.”
“Using our new surgical refactoring tools, if we can identify only the functionality that requires us to cross process boundaries, we can cut those service concerns away from the rest of the behavioral concerns that you have in your objects. We would leave your objects mostly intact, move the factory along with your service layer behind a dynamic proxy implant, defer the delegation of only persistence calls to the dynamic proxy implementation class and based on configuration either do a service lookup or simply delegate calls to our in process object.”
I paused. The patient looked a little green in the gills. “I think I’m going to need to see this on a whiteboard” he said.
“Ok, let’s draw this out” I said, and grabbed a marker
We’ll take a class like Person as an example:
“What are the responsibilities that simply must be executed on the service side of your application?” I asked.
“The persistence stuff”. He replied.
“Excellent. We’ll move only the persistence stuff inside of our WCF service, creating a service class for each persistent object. We’ll end up with a PersonPersistenceService, a DogPersistenceService, a TruckPersistenceService etc. You get the idea. Using your code generation, this shouldn’t be a big deal. These will be the services we expose through endpoints.”
“Since we don’t want to generate or write or maintain that logic twice, when we create our Person class, we’ll inherit from PersonPersistenceService.” Our Person class will also implement the IPerson interface that we created so that we can substitute a dynamic proxy for an actual Person object when the factory is used to get a Person object. The IPerson interface extends another custom interface called IPersistable. It has generic Save, Update, Delete, and Load methods that are implemented by using our PersonPersistenceService methods. Our Load method will use the Specification pattern (a close cousin of the Command pattern) taking in a specification (we’ll call it a QuerySpecification) of what we expect to load. This way we have a generic representation for loading sets of objects no matter what type they are or what the query represents. Finally, our Factory class will use the Cramon.DynamicProxy library to substitute a dynamic proxy for a real object. All method invokations on our proxy will flow to a custom DynamicPersister class which contains the logic to either route method calls to the object being proxied, or to a corresponding WCF service that persists Person objects. By the way, our Person object is marked up with DataContract attributes to selectively cull out state information. It would be nice if we could have marked up our IPerson
interface instead but WCF requires data contracts to be codified as concrete classes.”
The drawing looked something like this when I finished talking:
“Ahh I see,” he said.
“So, are you ready to go under the knife?” I asked.
to be continued…
(note: I do not suppose myself to be an actual Doctor of WCF.)