In my last work-related post, I described (the transition from my old workplace to my new one. In it, I briefly mentioned the project I’m working on. In an upcoming series of posts, I’ll highlight some of the technical challenges I faced while creating the object mapper service.
First, let me describe the object mapper service. Out there somewhere in the company, there exists a handful of Java applications that interface with a legacy application to get some data. That data is now also exposed by a .NET application I’ll call the DataStore, so the goal is to retire the legacy application.
To do that, we’re putting in place a .NET web service written in C# 2.0, which will accept requests from each of those Java applications. It takes the request, convert it to a DataStore request, execute the request, and then take the DataStore’s response and convert it back into a response object that Java application can consume.
Most of the work of the web service is accomplished by passing messages from the Java application to the DataStore and back. However, the web service does need to convert requests and responses. Hard-coding the web service to do that would introduce some unwanted dependencies on the Java applications and the DataStore. Any time one of their requests or responses changed structure, the web service would need to change as well.
Instead, I’ve created a component that uses an XML document that describe how to map objects of one type to another to drive the conversion process. This is the object mapper.
The next post will describe the domain model of the object mapper.
I embarked on an adventure last month, leaving my old job after eighteen months to re-enter the world of consulting.
When I started at the old firm, I thought of myself as just a computer programmer. I had reached a plateau at the home-building firm where I’d cut my teeth and had arrived at that position ready for a new challenge.
The first week, I was asked to add an enhancement to an application I hadn’t seen before. They wanted the capability to alter an HTML control’s text via an XML configuration file. I turned it around quickly, and developed a good reputation.
It turned out that the department had just started using agile and were having trouble getting over the hump. At my prior position, we’d been doing Scrum for a while and I said I could get it going there. They gave me a team of eager people and we were wildly successful. We got the rest of the department on Scrum, and our department managed to nearly double our output. I became a key part of the team, someone whom management and fellow developers looked to for leadership.
Sadly, it was not to last. We sold our product to a large customer overseas, and we were not ready to support that customer as though the product were a custom application. Meanwhile, the company I worked for had been acquired just as I hired on, and this overseas deployment brought scrutiny and change from the main office. As their culture and decisions supplanted our office, our agile ways and product vision met with more resistance.
I believe that friction led to some key leadership departures, and the magic that dwelt in that place dwindled away. I was even given the role of lead architect, but I quickly came to realize it was a quixotic quest and one not to be combined with a promotion. So, I sought my fortunes elsewhere.
My current position is a stark contrast to my architect position. My sphere of influence went from office-wide to cubicle-wide overnight. Most of my co-workers work in another state, and I feel isolated from the people I work beside.
The work is somewhat different from what I expected, too. I imagined technical challenges in decommissioning a certain piece of legacy middleware and replacing it with an adapter web service. We started by building a mapper service that can convert a type to an arbitrary type driven by an XML specification, for use on request and response objects.
A week in, I realized I was building something akin to ObjectBuilder or an IoC container. The constraints of the project hampered some tasks. For example, I had to fight to use unit tests, and I was asked to deliver a solution without any third-party libraries such as MbUnit. I was limited to VS 2005, C# 2.0, and ASMX web services.
I did have some latitude, though. I architected the whole solution. In the beginning, I though I was going to have to implement my own version of LinqBridge, but I found that the Composite and Decorator patterns led to some simple structures with powerful functionality.
I used TDD and ReSharper to amaze my co-worker with my quick delivery and robust code. My tests are in MbUnit, and I’m glad to report that during the development effort, the solution never dipped below 90% coverage as reported by PartCover. Initially, I didn’t have access to their source control (VSS), so I installed Subversion locally and used Tortoise SVN to write to a repository on my network drive, which is where my tests still safely reside.
Sadly, though, I did not run into the kind of design challenges I was hungry for in building this component. However, I must say that I’ve leveraged the Reflection library much deeper than I had before. The most interesting piece was conditional mappings, which I implemented as delegates.
Going forward, it looks like I will be doing analysis of their legacy Java systems, detailing their old object and data models. Once done, systems analysts will be able to map the legacy application to the new infrastructure, and we can create an adapter web service with the help of that mapper component we wrote.
This post talks about the IronRuby engine we built. Our application has a requirement that certain elements of program logic must be able to be changed without a deployment. The application’s initial architecture involved compiling C# functions on the fly, but it ran into memory pining issues after several hundred function sets had been loaded, which brought the application down every so often. Our team was charged with the task of preventing this situation while maintaining the feature.
We debated two approaches. We chose to use an interpreted script solution over a plug-in architecture because interpreted scripts are ideally suited to oft-changing code. Also, the logic is currently stored in XML files, and Ruby requires less character escaping than C# does when represented in XML. IronRuby won over IronPython because our team had a little experience with Ruby and none with Python.
The heart of the solution is a C# class called the IronRubyScriptEngine. In order to play along, you’ll need to include the following assemblies from the IronRuby 0.5.0 distribution:
Here’s the engine’s constructor:
As you can see, creating an IronRuby engine in C# is very easy.
We pass parameters into our engine with a method called SetParameter. More on this in a moment.
The real work is done inside the Invoke method, which wraps a snippet of Ruby code in a Proc. It dynamically creates the correct input parameter syntax, interprets the snippet, then invokes the script with the values of the parameters.
Let’s say I have a Person class, and I want to determine if the person is happy. By using SetParameters, I can associate an object with a parameter name, so that if I write a snippet bob.happy?, the engine creates Proc.new {{ |bob| bob.happy? }} and when called, my Person class instance is passed in.
As most Ruby afficionados know, Procs and Lambdas differ in how they handle the return keyword. We chose Lambdas so that return exits the scope like it would in a C# method.
ToDelimitedString is a simple yet handy extension method on IEnumerable.
With this engine in place, it was easy to migrate our existing logic into Ruby functions. The final version of the engine includes script caching, so we don’t interpret the same function over and over.
As the migration proceeded, we decided to refactor some of the logic to re-use code, something that was difficult in the old architecture. In Ruby, it’s easy to extend a class. In IronRuby, you can certainly do that with CLR classes as well. However, the classes we needed to extend exist on the wrong side of a Remoting boundary. Extending an anonymous RemotingProxy of the class proved tough, so we chose to extend the object instead.
In the snippet, we apply the extension with the following code:
Between the terseness of Ruby and re-use of code, we have much less code to maintain. Although the Ruby functions are slower than their C# counterparts, they are certainly performant enough for our scenario.
I hope this post has been interesting. Comments are welcome.
JP Boodhoo brought his Nothin’ But .NET class to Denver for the first time. My co-worker had taken the class last year and raved about it. It really improved his game, and we persuaded our company to send five of us to this one.
It’s worth its weight in gold.
JP introduced fundamental programming design concepts, then had us work in small groups to complete challenges, working towards a goal of designing an application top-down with test-driven development. All of us learned that we did not understand some of these basic concepts as well as we should. JP opened my eyes to a whole new level of encapsulating and dividing code; it was like discovering that atoms are made up of smaller particles.
Don’t get me wrong: it’s a ton of work. On Thursday and Friday, we met for breakfast at 8:30 and coded till 4 in the morning – that’s 15-20 hours a day. Especially as fatigue set in, the challenges become so hard that we as a class struggled to complete them. Some days we ate at the same boring fast food restaurants again and again so we could get back to coding. We as a class worked hard together and became friends.
JP is a master programmer. I mean that in the sense of a martial arts master. He is human, after all, but he has honed his skills and become an expert. Things we had to intellectualize just flow from his heart and mind to his hands at an astounding rate.
Yet the course was more than programming; it was philosophy. We spent a lot of time talking about where we’ve been, what made us choose programming, where we stand today, and where we’re headed with our lives. It was food for thought for some, a wake-up call to others of us. I certainly have formed some plans to achieve some goals I’d only fantasized about before.
I used to use DiffMerge as an alternate file compare/merge tool, but I’ve found that under StarTeam 2008 Release 2, it now leaves annotation artifacts in my file, something like this:
[newer file]
Since I’m working in C#, the compiler doesn’t take too kindly to literal symbols in the middle of its files. For the time being, I’m resigned to using StarTeam’s built-in tool.
One day, however, the built-in File Compare/Merge tool stopped working on me. The progress bar said “Finding Differences…”, flickering from left to right, never completing.
I resolved the issue by stopping StarTeam and deleting the syncdb folder under my Local\SettingsApplication\DataBorlandStarTeam folder.
I hope this information helps someone. I wasn’t able to find another page describing this. Anybody else have this issue?