Anyone who’s been in modern business computing for any real length of time has likely been presented, and in multiple contexts, with the challenge of storing and retrieving object data to/from an underlying data store. Object-relational mapping tools can make this easier and lead to cleaner, more maintainable code–but the devil’s in the details of the ORM implementation, as briefly explored below.
One might be tempted to think that any ORM is a good ORM, at least as offering general advantages over naked item access, but in practice this is not always true. I’ve found that direct API access to items is far more convenient, reliable and maintainable than a badly-implemented ORM. Type safety is not the only measure of maintainability of object-oriented code which access a data store. Efficiency of coding, clarity of the object structure, and ease of maintenance–which cannot be measured by speed of generating a code template in the first place, but must include an assessment of how long updates may take–can be more important on a practical basis.
In general, use of a well-maintained de facto standard such as the Sitecore Glass Mapper will offer many advantages, from the design of the ORM code itself, to less cluttering of the domain model, to decreased ramp-up time for developers new to the team. I’ve learned this the hard way, and of all home-grown toolsets, ORMs can lead to the most disadvantages long-term, perhaps only rivalled these by badly-written local CMSes. Eventually, one simply has to cut the cord.
Item-wrapping, homegrown ORMs can be tantalizingly easy to write, but lead to drawbacks
At one company a sprawling codebase, put together by different developers over time and using different styles and approaches, included the use of a code generation tool designed to be used as an ORM. The way this tool worked, one would invoke the tool, template data would be loaded, and a basic interface and class file would be generated. One could copy the code into one’s working directory and include it in a project. Fields were wrapped for type safety. Easy peasy, right?
Code updates with an item-wrapper-generating ORM, whenever a corresponding structure changes in the CMS, can be a major hassle.
Not exactly. Code updates with an item-wrapper-generating ORM, whenever a corresponding structure changes in the CMS, can be a major hassle. If any changes have been made to the object code since initial auto-generation, updates necessarily involve merging (often manually) a newly-generated code file with the older, customized file, so that crucial information isn’t lost.
In my experience, a typically clunky implementation also tends to obscure the natural class and inferface model of the code, introducing clutter and bad design for no reason. So, for example, a typical implementation may have a particular code file, based on a Sitecore template which extends another template, only include that item’s fields. “But wait,” one may think, “isn’t that okay, as long as any inherited templates can be generated as well, and the subclasses linked to parent classes/superclasses?” That is certainly true, except that, regrettably, often homegrown and other badly-done implementations don’t do this easily or at all, leaving the developer to create–and reapply in case of changes and code re-generations, commonly leading to time-wasting maintenance errors–those linkages.
In extremely bad cases, where a generated wrapper class contains field ID-name mappings as well, those are not cleanly reflected in the inheritance model; I’ve seen auto-generated field names hiding ones from inherited classes/templates, i.e. inherited field names not being available on subclasses, obscuring the programming model. In my experience, a naively made ORM may be accompanied by code accessing item fields directly using these names, either through sheer bad programming practice by subsequent developers befuddled by the arrangement, or because of the need to work around limitations of the ORM. And, to cap it all off, direct item and field access may only be available with clunky-looking calls to methods or properties, if at all; and the ORM itself may begin to take on the character of a badly constructed API, where its base classes have loads of badly designed “helper” code.
A main problem with a badly written ORM is that it typically obscures the domain object model, which out of the entire codebase can be the most important to keep clean. By far the best maintainability of ORM-using code results from a tool which can at least keep any mappings outside of the domain model proper, and which ideally leads to a clear, declarative programming style. (In Sitecore, essentially an ASP.NET website providing a C# API, one’s thoughts naturally turn to the use of attributes; this is a clear advantage for the Glass Mapper, discussed below.)
The main problem with a badly written ORM is that it typically obscures the domain object model, which out of the entire codebase can be the most important to keep clean.
Unfortunately, the more an old, home-grown ORM is used, the more it may become part and parcel of an entire local codebase, taking major effort to extract. Even worse, developers who created the ORM may become emotionally invested in its continued use, resisting change. In all cases it is, in my experience and opinion, best to nevertheless adopt a more modern approach. Otherwise, the technical debt simply continues to increase over time, spread over many deliverables where it is not easy to track.
The Custom Item Generator: somewhat better, but only just
The Sitecore Custom Item Generator is a free module available on the Sitecore Marketplace, which essentially takes the item-wrapping approach described above, but is of higher quality than typical homegrown item-wrapping ORMs in my experience. When I first began working with Sitecore, it was on a codebase making extensive use of the Custom Item Generator, and at least it did not involve a steep learning curve.
The CIG was also implemented at a time when the Glass Mapper was not available, and in an honest attempt to make life easier for developers, so it’s best viewed charitably. Still, it offers many drawbacks which need not be explored to death here, but again notably include the need to manually regenerate classes in case of Sitecore data model changes, and then manually merge the updated auto-generated code with any customizations in the codebase. I’ve actually seen code making direct item access which was cleaner and more maintainable than CIG-using code; especially with a well-written set of extension methods, item access can actually be fairly simple and straightforward, and essentially self-documenting.
Writing the C# code for a cleanly designed class and interface model is typically the least of a developer’s worries, and usually involves a negligible amount of time.
There are other code generation tools which work with Sitecore items, such as Hedgehog TDS Code Generation. They essentially work by accessing a template via the Sitecore API, then generating a corresponding C# code file, and as such may be seen as helpful in initially generating interfaces and classes. However, these tools should not be confused with the advantages of an ORM, and can still offer drawbacks such as necessitating merges with updates. Writing the C# code for a cleanly designed class and interface model is typically the least of a developer’s worries, and usually involves a negligible amount of time.
Enter Glass, the greatest thing since sliced bread
The Sitecore Glass Mapper was written with all of these past shortcomings in mind, and designed to eliminate them. Sliced bread’s pretty great, but can it magically pull up item data from Sitecore (or Umbraco) and map field data to type-safe properties, and support looking up related item data with a declarative syntax, while preserving your clean object model and isolating it from rework in case of changes to the data model? No sandwich can do such a thing, no matter how cleverly made.
The benefits of Glass are fairly well-documented at the project’s site, and thus I won’t exhaustively get into them here (and though the documentation used to be a bit outdated in parts, it’s undergone an upgrade).
On one large project I recommended adopting Glass for new development, where previous Sitecore work had used the Custom Item Generator. This particular project featured a fairly detailed set of classes and corresponding set of templates and branch templates, to simplify creating a new instance of a particular structure, which would happen on a frequent basis. Elements within the subtree needed to be able to refer to each other at their relative locations, as well as data in a shared global area.
On that project and others, the ability to use Sitecore Query expressions in Glass attributes simply worked wonders. It became a snap to wire the entire object structure together and pull the data up correctly, without the need for custom development; the work of generating the object structures in memory became as simple as declaratively including a few paths, which again made the project nearly self-documenting. Providing reusable functionality with the use of a base Glass class and extension methods was a snap. Especially in this project’s read-heavy typical use pattern (which, let’s face it, underlies the entire architecture of a web CMS like Sitecore), the Glass Mapper’s caching support worked well too. Work has now also been done toward letting users optionally pull Glass data from a Lucene index.
I saw first-hand the massive improvements in ease of maintenance and overall code simplicity that an ORM like Glass offers…
On that first large project using Glass, I saw first-hand the massive improvements in ease of maintenance and overall code simplicity that an ORM like Glass offers when compared with item-wrapping approaches. Since then I’ve run across occasional situations where Glass loading code would fail to locate a class across boundaries, such as within a WCF service, but each time the problem was straightforward to understand and solve, so I consider Glass to have relatively few drawbacks. Anyone implementing Sitecore for the first time would do well to investigate the Glass mapper.