Introduction
All useful software, no matter what the languages or technologies or processes used to create it, is developed to serve a need for a particular domain. I will simply call this need the Domain Vision. We need to move from the current situation, the Current Domain, towards meeting that need. The new need could involve creating a new system from scratch, replacing an existing system, or merely adding a feature, it doesn't matter in this discussion.
Ideally, when we develop new software, we march along effectively and efficiently in a Short Path towards a clear vision. More often, we have hiccups along the way in a Long Path towards a vision that either isn't clear to begin with, or evolves significantly as we progress towards it. Worst case, we develop software along a Dead End Path towards something that ultimately isn't part of the vision.
As software developers, we strive to get as close to the short and efficient path as we can, and there are many techniques, processes, and technologies to help us do that. The focus of this article is on the bag of techniques and technologies that fall under Model Oriented Development
. You already are a model oriented developer! You undoubtedly already utilize some of the techniques outlined here. The purpose of this article is to put techniques you already use into context of overall techniques that you may find useful to tap into.
Model Oriented Development
Model Oriented Development (MOD) is a technique that allows you to utilize a model for development purposes at any point in the development process. You translate model information into source code and/or utilize the model directly during the course of development. This doesn't imply any particular process or technology. How you represent and utilize your model is completely up to you.
Consider the following diagram. Any form of MOD can help you more clearly define the Vision, further represented in terms of Ideas, Requirements, Design, and ultimately Code.
There are four basic forms of MOD that will be covered in this article: Informal, Inline, Coupled, and Decoupled. These aren't industry standard terms, as I haven't seen standard terms for these forms. I listed a few techniques and technologies that fall under these forms that are probably familiar to you.
Before going on, I would like to emphasize two points. First, I am not implying that a certain process such as Waterfall or Scrum should be followed, nor will I cover any form of process in this article. Ideas progress into requirements, design, and code, and this is certainly true whether or not you are solving small problems in your domain iteratively or trying to tackle the whole domain in phases. Second, the form of MOD you choose to utilize is not an either/or choice. It is often very useful to utilize techniques from more than one of these forms anywhere from ideas to code.
I will describe each of the forms of MOD in the sections below, focusing a little bit on how models can be represented and utilized. I will outline some advantages and disadvantages based on my personal experience and observations working mostly in startup environments, and inject my personal preferences as a little or a lot. I think each form can be very useful, and each form can become burdensome for a given situation if taken too far.
Informal Model Oriented Development
When you have an idea in your head about some software you need to write, that idea is some form of abstractual representation of the code you need to write towards the vision you need to accomplish. That idea is a model!
When you are working on a team towards a common vision, you need to communicate and share your ideas to the point where there is a common understanding, where everyone is speaking the same language so to speak. You might do some white boarding and represent or document these ideas somehow in terms that the team understands and agrees to. You might further elaborate those ideas as requirements or even design ideas. If you do any of this, you are a model oriented developer, elaborating your model utilizing informal techniques.
Informal MOD can be roughly defined as:
- Having an ad hoc model definition outside of your source code. The models might just be ideas in your head, written descriptions, drawings, or diagrams of your own design or standard.
- There are no software tools that can interpret your model definition.
- There are no software tools that can translate model information into source code. You translate information to code manually.
For example purposes, our vision will be a little hotel management web site, where we want to be able to track guests that stay in our hotels. Following is a little whiteboard drawing that models the basic ideas and requirements:
Advantages
The main advantages for Informal MOD include:
- Ideas - This technique is probably the best approach for initially discussing ideas without being encumbered by having to represent the ideas in a formal model.
- Requirements - If the vision is for a relatively simple domain and/or one that can easily be observed by working software (ie no complex underlying rules and behaviors), an informal approach to defining and utilizing your model should work just fine.
- Design and Code - Designing and writing code is easy, without being encumbered by model definitions. Customizing your code is just as easy.
- Team - Informal approaches work well with small teams, where the effort at getting the common understanding is relatively smaller.
Disadvantages
The main disadvantages for Informal MOD include:
- Requirements - For more complex domains, lack of a formal model can make it more difficult to validate requirements and ensure consistency of requirements. This increases the risk of taking the long path to the vision, or even worse, embarking on a dead end path if the team realizes the software doesn't align with the vision.
- Design and Code - Depending on the complexity of the domain, organically designing and coding without the context of a more formal model could result in more code duplication and/or need to refactor code, increasing the path to the vision.
- Team - Informal approaches start to break down as the team gets larger and geographically distributed.
Testing and Maintenance
Informal MOD typically provides no specific benefit for testing and maintenance. If informal models are diagrammed and written down at all, they tend to be developed for initial understanding only. As with code, writing tests is easy. For downstream changes, you generally have to rely on the quality of the legacy code and test cases to understand original intent, and how changes will impact that.
A Little or a Lot?
I always utilize at least a little of this form of MOD, especially for discussing initial ideas and often while coding. For small teams and small simple projects, I do a lot of informal MOD.
Inline Model Oriented Development
The inline form of MOD is very popular these days with the advent and use of a number of frameworks that greatly enable you to effectively design and develop your applications. Inline MOD can be roughly defined as:
- Having a formal model defined in your source code. That model is usually relevant to a particular layer in your application.
- Having a framework that can interpret and utilize your formal model definition. The framework has supporting software to allow you to utilize the model and/or provide a mechanism to translate (generate) from the model some of your software for you.
A good example of an inline form of MOD is an ORM such as Entity Framework or NHibernate or Dapper. With an ORM, you define your model in code and/or load it from a database definition, and the framework will typically manage your db schema (sometimes generating stored procedures). An ORM will typically make it easy to manage your data transactionally with a minimal amount of additional code. VITA is a particularly powerful ORM for managing your data and providing additional building blocks such as authentication rules based on your model. Below is an example VITA model definition for our little hotel management system:
[Entity(Name="Hotel", TableName="Hotel")]
[Paged, OrderBy("Name")]
public partial interface IHotel
{
[Column("Id"), PrimaryKey, ClusteredIndex(IndexName="PK_Hotel"), Auto]
Guid Id { get; set; }
[Column("Name", Size = 50), Index(IndexName="IX_Name")]
string Name { get; set; }
IList<IRoom> HotelRooms { get; }
}
[Entity(Name="Room", TableName="Room")]
[Paged]
public partial interface IRoom
{
[Column("Id"), PrimaryKey, ClusteredIndex(IndexName="PK_Room"), Auto]
Guid Id { get; set; }
[Column("Number"), Index(IndexName="IX_Number")]
int Number { get; set; }
[Column("MaxOccupancy")]
int MaxOccupancy { get; set; }
[EntityRef(KeyColumns = "BuildingId")]
IBuilding Building { get; set; }
}
[Entity(Name="Guest", TableName="Guest")]
[Paged, OrderBy("Name")]
public partial interface IGuest
{
[Column("Id"), PrimaryKey, ClusteredIndex(IndexName="PK_Guest"), Auto]
Guid Id { get; set; }
[Column("Name", Size = 50), Index(IndexName="IX_Name")]
string Name { get; set; }
[Column("Email", Size = 150), Index(IndexName="IX_Email")]
string Email { get; set; }
IList<IReservation> GuestReservations { get; }
}
[Entity(Name="Reservation", TableName="Reservation")]
[Paged]
public partial interface IReservation
{
[Column("Id"), PrimaryKey, ClusteredIndex(IndexName="PK_Reservation"), Auto]
Guid Id { get; set; }
[Column("ArrivalDate"), Index(IndexName="IX_ArrivalDate")]
DateTime ArrivalDate { get; set; }
[Column("DepartureDate"), Index(IndexName="IX_DepartureDate")]
DateTime DepartureDate { get; set; }
[Column("NumberOfOccupants"), Index(IndexName="IX_NumberOfOccupants")]
int NumberOfOccupants { get; set; }
[Column("Rate"), Index(IndexName="IX_Rate")]
decimal Rate { get; set; }
[EntityRef(KeyColumns = "GuestId")]
IGuest Guest { get; set; }
[EntityRef(KeyColumns = "RoomId")]
IRoom Room { get; set; }
}
Many UI oriented frameworks are built upon the MVC (or MV whatever) design pattern, and of course a model is at the heart of this. The frameworks do much of the leg work, making it easy to use your model to bind to views, validate, update data to the server, etc. Backbone.js is an example where the model is pretty front and center, and below is an example model definition (with just a little bit of validation added):
var Room = Backbone.Model.extend({
defaults: {
Id: "",
Number: 0,
MaxOccupancy: 0
},
validate: function (attr) {
if (!attr.Number <= 0) {
return "Invalid Room Number supplied."
}
}
});
var Rooms = Backbone.Collection.extend({
model: Room
});
var Hotel = Backbone.Model.extend({
defaults: {
Id: "",
Name: "",
HotelRooms: new Rooms()
},
validate: function (attr) {
if (!attr.Name) {
return "Invalid Hotel Name supplied."
}
}
});
var Reservation = Backbone.Model.extend({
defaults: {
Id: "",
GuestId: "",
RoomId: "",
ArrivalDate: undefined,
DepartureDate: undefined,
NumberOfOccupants: 0,
Rate: 0
},
validate: function (attr) {
if (!attr.NumberOfOccupants <= 0) {
return "Invalid Number Of Occupants supplied."
}
}
});
var Reservations = Backbone.Collection.extend({
model: Reservation
});
var Guest = Backbone.Model.extend({
defaults: {
Id: "",
Name: "",
Email: "",
GuestReservations: new Reservations()
},
validate: function (attr) {
if (!attr.Name) { return "Invalid Guest Name supplied."
}
}
});
Advantages
The main advantages for Inline MOD include:
- Design and Code - Frameworks provide a number of benefits:
- Models are easy to define and understand in code.
- Frees developers from writing support code in utilizing the model.
- Helps enforce standard practices around the use of the model.
- Team - Utilizing frameworks towards a common standard works well for teams large and small.
Disadvantages
The main disadvantages for Inline MOD include:
- Ideas and Requirements - This technique isn't particularly suited to elaborating or communicating ideas and requirements (especially to non-developers). It is probably better to utilize a different MOD technique for ideas and requirements.
- Design and Code - If there are too many frameworks in use with their own repetative model definitions, it can become burdensome to keep these models in sync.
Testing and Maintenance
Inline MOD typically provides at least some benefit for testing and maintenance, depending on the framework(s) used. At the very least, a framework's model provides some context in understanding previous intent and impact of changes. Having less code to write and/or having some boilerplate code (re)generated for you reduces maintenance costs. Some frameworks have built in features (such as Entity Framework migrations) to help in maintaining and deploying changes.
A Little or a Lot?
If the technical requirements and team best practices favor the use of frameworks at any layer in the system, I favor using a lot of this form of MOD for design and coding.
Coupled Model Oriented Development
The coupled form of MOD was probably more popular in the 1990s and early 2000s, with a number of different modeling approaches that eventually congealed to the standard that is UML, with a number of processes and tools that evolved around that standard. Coupled MOD can be roughly defined as:
- Having a formal model defined outside of your source code.
- There is a strong correlation (often one-to-one) between model elements and your source code. Thus, the model incorporates elements of software design.
- There are software tools that can interpret your model definition.
- There are software tools that can translate model information into source code.
Many of the UML diagrams are intended to clarify the design of a system, and technically UML diagrams that model users and general abstractions and behaviors would fall under the decoupled form of MOD, explained later. Below is a class model that outlines the class and interface design for our little hotel management vision:
Taking this approach to code, there are numerous tools out there that generate code from UML models. Some notable examples include Rational Software Architect, Rational Rhapsody, and Altova. Note that some UML code generation tools such as Visual Studio class designer or Umple fall into the Inline MOD form.
I chose Altova to create some models and generate some code from it. Altova seems as good as many of the coupled MOD tools out there. Here is the class diagram in Altova:
Here is some code generated from the above model:
public interface IHotel
{
System.Guid Id
{
set;
get;
}
System.String Name
{
set;
get;
}
}
public class Hotel : IHotel
{
public Room[] HotelRooms;
public System.Guid Id
{
set{}
get{}
}
public System.String Name
{
set{}
get{}
}
}
public interface IRoom
{
Guid Id
{
set;
get;
}
int Number
{
set;
get;
}
int MaxOccupancy
{
set;
get;
}
}
public class Room : IRoom
{
private Reservation[] RoomReservations;
public Guid Id
{
set{}
get{}
}
public int Number
{
set{}
get{}
}
public int MaxOccupancy
{
set{}
get{}
}
}
public interface IGuest
{
Guid Id
{
set;
get;
}
String Name
{
set;
get;
}
String Email
{
set;
get;
}
}
public class Guest : IGuest
{
public Reservation[] GuestReservations;
public Guid Id
{
set{}
get{}
}
public String Name
{
set{}
get{}
}
public String Email
{
set{}
get{}
}
}
public interface IReservation
{
Guid Id
{
set;
get;
}
DateTime ArrivalDate
{
set;
get;
}
DateTime DepartureDate
{
set;
get;
}
int NumberOfOccupants
{
set;
get;
}
decimal Rate
{
set;
get;
}
}
public class Reservation : IReservation
{
public Guid Id
{
set{}
get{}
}
public DateTime ArrivalDate
{
set{}
get{}
}
public DateTime DepartureDate
{
set{}
get{}
}
public int NumberOfOccupants
{
set{}
get{}
}
public decimal Rate
{
set{}
get{}
}
}
As with most coupled MOD tools, you need to do a good bit of tweaking to the models and corresponding settings to get the code you want, and you'll often run into some limitations. For example, I didn't find the settings in the model to make C# properties automatic (instead having an empty {} implementation generated). Though Altova seems to do a good job of subsequent merges with your customizations such as making the properties automatic or adding your implementation details. As of this writing, I didn't find a way to make compositons and associations correspond to C# properties (using IList, etc.) instead of being generated as arrays.
Advantages
The main advantages for Coupled MOD include:
- Design - Modeling designs can add clarity to those designs and the overall architecture, and provide a means for the team (non-developers included) to validate those designs.
- Code - Tools that make direct use of your models in generating code can help reduce some of the grunt work.
- Team - Formal models can be useful for large teams, communicating information in a commonly understood and vigorous format.
Disadvantages
The main disadvantages for Coupled MOD include:
- Requirements - Detailed design models generally mask the basic underlying requirements, making it more difficult to validate those requirements.
- Design - Many of my colleagues over the years have shied away from models and modeling altogether, I think primarily from the experience (first hand or otherwise) of doing too much design modeling. At some point, creating and maintaining design models becomes as much (or more) of an effort as doing it in code, and I think most developers (myself included) would rather express designs in code.
- Code - Using tools to generate too much of your code (and the amount of modeling required to support your code) might become burdensome to customize to your needs and or evolve to the best practices you need to follow. This of course depends on the ability of the code generation tool of your choice to tailor when/how you want your code generated.
Testing and Maintenance
If coupled MOD models do a good job in providing a clear design context for the team compared to the corresponding code, they will be useful for outlining design changes and understanding potential impacts. If an effective code generation solution is employed for code and tests, the cost of maintaining and upgrading legacy code and associated tests can be reduced.
A Little or a Lot?
Personally, I favor other forms of MOD for almost any given situation over this one, so no more than a little of coupled MOD. Sometimes, I may do a few UML design models with the team to flesh out details of those designs within the overall architecture, and not generate code from those models.
Decoupled Model Oriented Development
With the heavier use of UML for specifying design, I think the decoupled form of MOD has had less attention in the industry in general. Decoupled MOD can be roughly defined as:
- Having a formal model defined outside of your source code.
- There is a weak correlation between model elements and your source code. Your source code is decoupled from the model. The abstract models tend to have very little if any design information. The detailed design is also decoupled from the model.
- There are software tools that can interpret your model definition.
- There are software tools that can translate model information into source code.
The key in recognizing this form is that the purpose of the models is to clarify ideas and requirements. UML use case/sequence/class/state/activity diagrams can be used to flesh out ideas and validate requirements sans design. Call me old school, but I still prefer using Shlaer-Mellor diagrams which help keep the focus on the requirements and the general data/workflow of the vision. Following is an information model for our hotel management system, with relationships described and formalized:
Taking this approach to code, I think there are few tools that do this well. Some template based code generators such as CodeSmith are probably most well known. Many of these tools can utilize an existing database as a source for model information, which reduces modeling efforts. A particularly effective tool for decoupled MOD will give you full control over managing your models (structure and data that you need), a powerful language to give you full control to program the design patterns to use in generating code, and complete ability to integrate with your custom code. Mo+ attempts to cover all of these bases.
One significant advantage of decoupled MOD tools over coupled ones is the ability to integrate well with inline MOD frameworks. It's just a matter of providing a means to map the decoupled model to specific ones for each framework. Following is a Mo+ property/template (without proper syntax highlighting) that is used to manage VITA ORM model interfaces (shown above) from a Mo+ model (which is a form of ER model that has elements that map well to the diagram above):
<%%:
<%%-/*<copyright>
%%>
<%%=Solution.Copyright%%><%%-
</copyright>*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using Vita.Entities;
namespace %%><%%=Project.Namespace%%><%%-.Models%%>
<%%=Solution.OPEN_BRACE%%><%%-
//------------------------------------------------------------------------------
/// <summary>This interface defines the key elements for managing
/// an associated table for %%><%%=VITAClassName%%><%%- items, utilizing
/// the VITA ORM.</summary>
///
/// This file is code generated and should not be modified by hand.
/// If you need to customize outside of protected areas, add those changes
/// in another partial interface file. As a last resort (if generated code needs
/// to be different), change the Status value below to something other than
/// Generated to prevent changes from being overwritten.
///
/// <CreatedByUserName>%%><%%=USER%%><%%-</CreatedByUserName>
/// <CreatedDate>%%><%%=NOW%%><%%-</CreatedDate>
/// <Status>Generated</Status>
//------------------------------------------------------------------------------%%>
<%%=VITAInterfaceAttributesCode%%>
<%%=Solution.NEWLINE%%>
<%%-public partial interface %%><%%=VITAInterfaceName%%>
var hasBaseEntity = false
if (BaseEntity != null && BaseEntity.VITAIsDataModelEntity == true)
{
hasBaseEntity = true
}
<%%=Solution.OPEN_BRACE%%>
if (hasBaseEntity == true)
{
<%%-
[PrimaryKey, EntityRef(KeyColumns = "%%>
foreach (Property where IsPrimaryKeyMember == true)
{
if (ItemIndex > 0)
{
<%%-,%%>
}
<%%=VITAPropertyName%%>
}
<%%-")]
%%><%%=BaseEntity.VITAInterfaceName%%><%%- %%><%%=BaseEntity.VITAClassName%%><%%- { get; set; }%%>
}
foreach (Property where VITAIsInterfaceModelProperty == true)
{
if (ItemIndex > 0 || hasBaseEntity == true)
{
<%%=Solution.NEWLINE%%>
}
<%%=VITAPropertyCode%%>
}
if (VITAIsPrimaryUserEntity == true)
{
<%%=Solution.NEWLINE%%>
<%%=Solution.NEWLINE%%>
<%%-UserType Type { get; set; } //might be combination of several type flags%%>
}
foreach (Collection where VITAIsInterfaceModelProperty == true)
{
<%%=Solution.NEWLINE%%>
<%%=VITAPropertyCode%%>
}
foreach (EntityReference where VITAIsInterfaceModelProperty == true)
{
<%%=Solution.NEWLINE%%>
<%%=VITAPropertyCode%%>
}
if (VITAHasFullNameProperty == true)
{
<%%=Solution.NEWLINE%%>
<%%=VITAFullNameProperty%%>
}
<%%=Solution.CLOSE_BRACE%%>
<%%=Solution.CLOSE_BRACE%%>
%%>
Below is some code generated from the above template. It is generally much easier to create and maintain high quality code with a decoupled approach.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using Vita.Entities;
namespace Forums.VITA.Models
{
[Entity(Name="Discussion", TableName="tblForums_Discussion")]
[Paged, OrderBy("Title")]
public partial interface IDiscussion
{
[PrimaryKey, EntityRef(KeyColumns = "PostID")]
IPost Post { get; set; }
[Column("Title", Size = 255), Index(IndexName="IX_Discussion_Title")]
string Title { get; set; }
[Column("DiscussionText"), Unlimited]
string DiscussionText { get; set; }
IList<IDiscussionReply> DiscussionReplyList { get; }
}
}
Advantages
The main advantages for Decoupled MOD include:
- Requirements - Doing a little modeling helps define the big picture for the team. Formal models that are tailored towards requirements can go a long way in terms of fleshing out the overall vision. These models can be used to qualify and validate requirements, and can help identify inconsistencies in requirements early on.
- Design - Since the detailed design is decoupled from the models, developers have the flexibility to define their design in code or any other means they see fit.
- Code - Tools that make direct use of your models in generating code can help reduce some of the grunt work. The combination of needing to do less modeling and being able to define your design patterns in code may make these tools more attractive than coupled MOD tools.
- Team - Formal models can be useful for large teams, communicating information in a commonly understood and vigorous format.
Disadvantages
The main disadvantages for Decoupled MOD include:
- Design - This form does little if anything towards clarifying designs for non-developers in the team.
- Code - As with coupled MOD, using tools to generate too much of your code from abstract models might become burdensome if taken too far. Again, it depends on the effectiveness of the tools used.
Testing and Maintenance
As decoupled MOD models provide context in understanding overall requirements, changes to these models can help clarify the impact of changes to requirements, and help in planning of design changes. If an effective code generation solution is employed for code and tests, the cost of maintaining and upgrading legacy code and associated tests can be reduced.
A Little or a Lot?
For fleshing out ideas as requirements, I find that I use decoupled MOD a lot. I always gravitate towards this form, even if I'm only doing a little modeling for my own understanding. I use Shlaer-Mellor and/or UML diagrams for this.
For codifying design patterns and using tools to generate code, that depends. I often do this for rapid prototyping ideas, especially those that utilize inline MOD frameworks. In order to choose to use a tool to maintain production code, I ask these questions:
- Does the (quality, not quantity) generated code come very close to what I would create by hand according to team practices? Generating a bunch of unneeded, duplicate, or compromising code has no use in production.
- Does codifying the design patterns used by the tool save time and help ensure consistency?
- Can codified design patterns (and generated code) be upgraded as needed to handle emerging technologies and practices?
- Can maintaining the generated code seamlessly integrate with custom code?
- Can we stop using the tool at any point with no adverse effects to maintaining production code?
If the answer to any of these questions is no for a given situation and tool, I wouldn't use that tool for maintaining production code.
In Conclusion
A little Model Oriented Development in any form can be useful in helping the team develop software in a shorter path towards a clear vision. Find the balance of using any of these forms that is right for your team for any given situation, and recognize when doing too much of a given form of MOD is becoming more of a burden than a benefit. Hopefully this article has given you a few ideas on MOD techniques and when you may want to employ them.