Architecting on Force.com
At CODA we are heavily into the implementation of design patterns within our Java and .Net based products, and as such found ourselves quickly wanting to benefit from them on the Salesforce platform as we embarked on our CODA2go project to build a new Finance system. To date we have implemented Domain Model, Unit of Work, Identity Map, Lazy Load, Data Mapper and Service Layer. The platform also provides a solid implementation of the Model View Controller pattern through its new Visualforce technology.
It’s very likely that CODA is amongst the first, if not the first software vendor to implement these patterns on this platform and I’m pleased to say despite the infancy of the Apex language they have taken very well. For those unfamiliar with design patterns, think of them as generic cook books for developers that describe solutions and strategies to building well structured and critically, well defined, consistent and thus maintainable implementations. This Wikipedia article is a good general reference. The above links are taken from Martin Fowler’s excellent site.
Implementing these patterns alongside a representation of our product’s domain model has also been critical to our desire to keep code relating to aspects such as business logic, data representation, querying, persistence and user interface code separate. This approach has been base architecture design for all CODA products ever since our first client server application, CODA-Financials.
The Force.com platform provides developers with Apex objects that reflect objects defining your application’s “schema”, which in turn is defined by the developer through the web interface or more recently in the Eclipse toolset offered by Salesforce. Currently the resulting Apex objects (so called SObjects), are not what you might regard as very “Bean like” and have no scope for adding behaviour through inheritance. As such they tend to feel to us more like they represent an application’s data model (although some declarative validation rules can be defined) as opposed to its domain model, where data and behaviour are defined together. For this reason we tend to view and refer to SObjects on the platform as DTO’s (Data Transfer Objects) for use within our persistence layer (see Data Mapper). In discussions with Salesforce architects we choose to implement Apex classes that at a basic level can be said to wrap these objects, but in fact form the basis of what has become the core layer of the CODA 2go implementation, the domain model layer.
There are many ways of adding business behaviour to your Force.com application, by coding in various forms and places to suit your immediate requirement. By using a combination of triggers, custom buttons, SControls (HTML snippets), JavaScript, Web Services and more recently Apex code handlers on Visualforce UI controllers. CODA needed to define an implementation strategy that would withstand the increasingly complex business scenarios each sprint would bring as our new Finance application continues to grow over not only its initial release sprints, but continue through its life (our current CODA-Financials product is over 12 years old and still being actively developed!).
So our strategy needed to be one that would provide a clear and easy-to-follow code partitioning model driven by the purpose and responsibility of the code being written by the developer. Thus we have one simple rule; only pure business logic goes into our domain layer Apex classes and nothing else. Standard methods such as canDelete, canUpdate, validate etc. exist on each domain class to provide consistency for common behaviours. This isn’t to say we ignore the other areas of the platform where code can get invoked - quite the opposite, the Force.com trigger feature is key to the validation phase our domain objects go through when being committed to the database via the unit of work. Except that in the CODA case the trigger implementations are pretty general in nature, in fact we have now generalized these. Thus simply, their role is to establish an instance of the applicable domain class for the trigger SObject (DTO) to delegate to. e.g. canUpdate and validate methods.
If you consider the addition of a business orientated Web Service layer to CODA 2go, we can be sure that Apex code implementing these services needs only interact with our domain model layer to invoke the exact same behaviour as our client interface exposes. Thus critically for any good API, ensure no business logic has leaked out into other areas such as the UI handlers. Something which is a common weakness in some application implementations, often leading to limited API exposure of the application functionality.
In our most recent sprint we have been considering our resource utilisation on the platform, particularly in respect to the amount SQL requests we make. Since this is a governed limit enforced by the platform we need to monitor this carefully. To this end we expanded our implementation of the Identity Map pattern through the code written in previous sprints that had not had this pattern applied. The results speak for themselves, in terms a significant drop in the number of SQL requests being made when compared with results from the same test (Creating Invoices) run on a previous sprint code base.
February 8th, 2008 at 5:48 pm
Thanks for the insight in what’s going on ‘under the covers’. While force.com gives us a great technical ‘platform’ to work with its clear that solid application development and design experience is required to create an industrial strength application that will perform well and scale.
February 10th, 2008 at 9:41 pm
Design pattern discussions often lead to more general debates on language choice. I’m often asked, in particular, to explain why the Apex language was devised for the Force.com platform, instead of just hosting Java or Python or some other well-liked language. After all, wouldn’t that get programmers started more quickly with their use of familiar patterns, instead of spending time on pattern re-implementation?
My first response is that Apex is the best way to talk to the Force.com environment. The Apex language and its engine can be aware of the application space, and can protect the developer from many potential misbehaviors in a way that a non-specific language would have to be heavily instrumented to match. You could do that — you could create all that design-time and run-time protective support, I mean, in PHP or whatever — but what’s the point?
I’m reminded of Paul Graham’s comment (in an excellent essay entitled “Revenge of the Nerds {http://www.paulgraham.com/icad.html}) on what happens when you try to solve deep problems with shallow languages: to “build cathedrals with toothpicks,” as it’s often been called. Actually, Paul was citing “Greenspun’s Tenth Rule” (http://en.wikipedia.org/wiki/Greenspun’s_Tenth_Rule) when he reiterated that statement that “Any sufficiently complicated C or Fortran program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp.”
The point is that good programmers take the best language that’s available on their target platform, and devise within that language a task-focused language suitable to their target problem. The closer you start to the end of step 2, the less time you have to spend on it and the sooner you start actually solving your problem. Implementation of patterns in that gap will be easier if the gap is smaller.
My second response is that it’s rare, any more, to see any useful application that’s written using tools that are not aligned with any specific platform. A Windows application written in pure ANSI C is still a Windows application, unless it’s just a TTY app that’s compiled to execute in a console window — not that there’s anything wrong with that, but it’s not what most users expect. In general, the user gets no additional freedom from an application’s being written in ANSI C, instead of (for example) C# or VB.Net. By the time the developer has effectively exploited the widgets and frameworks of any decent application environment, the question of what was used to stitch the API calls together is pretty much incidental to the question of how free the user is to employ the application as desired.
If an application needs a particular fat-client environment, it’s not a portable app, no matter how it’s coded; if it runs on any device with an Internet connection and a standards-conformant browser, it’s a portable app by any reasonably modern definition of the term.
When a language is suited to both the platform and the problem, design patterns can add value at a higher level of abstraction, and that’s a good thing. Putting powerful patterns on top of Apex is therefore a significant step toward the ever more general use of Force.com.