|By Ricardo Pardini, Eric Lemes||
|November 19, 2007 12:00 PM EST||
Mercado Eletrônico is the leading B2B company in Latin America. Founded in 1994, it provides services for supply chain management, such as e-procurement, catalog, sourcing and collaboration, based on an advanced technology platform supporting more than 30,000 transactions a day and a complex buyer/supplier user community.
The development of Mercado Eletrônico's technology platform started in 1994 using BBS software, which evolved to client/server and, in 1998, to the Web using Microsoft Active Server Pages. In 2005, with an accumulated two million lines of code ranging from stored procedures to AJAX interfaces, most of the code was complex and hard to maintain IDL/COM+ transactional components, implemented in a mix of Visual C++, Borland Delphi, and C#, and used by classic ASP and ASP.NET pages directly.
When .NET 2.0 was released, it was made the primary target for the new technology platform. It offered a great base library and excellent language support. As such, it was a natural choice since most of our code was already Windows-based. However, many years of watching and learning from the advances made in the Java community showed that application frameworks could make development simpler, faster, and easier to test compared to using the base libraries directly. Enter Spring.NET.
Mercado Eletrônico's architecture follows a traditional layered design as shown in the diagram in Figure 1.
Previous architectures started out with the same good intentions of having cleanly separated layers, but in practice the enforcement of this fundamental architectural principal broke down. No matter how hard we tried to keep our less experienced developers from mixing together data access, business logic, and user interface code, they couldn't resist the temptation to add references that would cross layers, e.g., database-specific code inside the business logic layer. The lack of a component in the architecture to help ensure proper isolation from the start resulted in a lot of work to refactor and keep things organized before the release.
Spring.NET addresses this practical concern in a simple and easy-to-follow manner through the use of its Dependency Injection features. Just as important, it provides additional features to help implement each layer.
The central components of Mercado Eletrônico's platform architecture and how they leverage Spring.NET include:
• Data Access: This layer is designed using Data Access Objects (DAOs) to interact with the database. The DAOs are split into two assemblies. The interfaces defining the data access contract are in one assembly and the implementations are in another separate assembly. This lets us code against the interface contracts, greatly enhancing testability and keeping the data access layer loosely coupled to the service layer. Our primary DAO implementation is built on Spring.NET's ADO.NET Framework, providing a simple yet powerful programming model that requires less code to implement typical data access operations. There is also a second DAO implementation based on the open source .NET object-relational mapping product NHibernate. Using dependency injection, swapping one implementation in and out is extremely simple. This gives us flexibility in easily changing parts of the application over time in a well-controlled manner.
• Services: The service layer contains our business logic and is also separated into interface and implementation assemblies for each service. The implementation is coded as a standard C# class agnostic to any distributed technology, a "Plain Old C# Object" or POCO. This lets us expose the same implementation as a COM+ component, a Web Service, or via .NET Remoting using Spring.NET's portable service abstraction features. In case we don't need to distribute the object, changing the configuration to use a standard .NET local in-process instance is easy. All of the services are also configured into each other and into the UI layer using Spring.NET. Spring.NET can then also apply declarative transaction management and business logging to the service layer through the use of its Aspect Oriented Programming features.
• UI layer: Web applications built using ASP.NET make use of Spring.NET's ASP.NET handler, so that we can configure and inject services into our pages just like any other object. Adobe Flex and AJAX applications benefit from using the configuration-exposed Web Services, saving a lot of work in repetitive coding.
Challenges and Spring.NET Benefits
Since our conversion from ASP/COM to .NET, Spring.NET has proved to be an incredibly effective tool for developing the complex, mission-critical applications required by our organization. Mercado Eletrônico has seen substantial improvements in a number of areas:
Loose Coupling and Dependency Injection
In addition to the practical issues previously mentioned regarding the development of a layered application architecture, there was also the common problem of how one layer gets access to its neighbors and how to swap different implementations in and out. Every team found a different way, each with its own associated problems, such as complex component registrations, failure-prone CreateObject() invocations, or even pre-processor directives.
With Spring.NET, our Data Access Objects are auto-wired into our service objects, which in turn are auto-wired into our client code, indirectly, using Spring.NET's dependency injection features. This allows for cleaner and more loosely coupled code, i.e., free of hard-coded infrastructure related lookups for collaborating classes. Since every layer only references the neighbor's interface, not a specific implementation, and gets an appropriate implementation injected via configuration, this allows for an easy external swapping of implementations. Even when there's only one implementation of a given interface, following this pattern lets us enjoy many other features of Spring.NET detailed below.
Most of our code was difficult to test due to the way data access and service classes were implemented, since it had implicit hard-coded dependencies on the runtime environment and other layers. With Spring.NET and its promotion of a code-to-interface style, we can more easily unit-test our code. For example, we could use mock implementations of our Data Access Objects to test business logic in our test cases without changing a single line of application code.
We were also able to use NUnit and its Spring.NET extensions for writing complete integration tests. These extensions can perform a transaction rollback on test case completion, allowing for more comprehensive test coverage and quicker test writing.