March 2014

Volume 29 Number 3

The Working Programmer : Getting Started with Oak: Data Validation and Wrapping Up

Ted Neward | March 2014

Ted NewardFor three columns now, I’ve been exploring the “dynamic-y” object approach that Oak brings to the Web application space, and it’s been an interesting ride, complete with a few challenges to long-held beliefs about how Web applications need to be built (or about the platform on which they’re built). But every ride has to come to an end sometime, and it’s about time to wrap up my exploration of Oak. I’ve got to figure out how to ensure data put into the system by the user is actually good data, for starters.

But first ...

Commentary

If you go back and look at the system as I left off last time, trying to add a comment yields another of those helpful errors, this time informing you that “Blog.Controllers.Blog does not contain a definition for ‘AddComment.’” Contrary to what might happen in a statically typed system—where the lack of this method would trip a compilation error at the front of the compile/deploy/run cycle—in a dynamic system, these errors won’t be seen until they’re actually attempted. Some dynamic-language proponents claim this is part of the charm of dynamic languages, and certainly not having to worry about keeping everything consistent across the entire system can be a great boon when the mind is on fire with an idea and you just need to get that idea out into the world. But most Ruby-on-Rails developers I know who’ve done a project larger than your typical Todo list application will be the first to admit that in a dynamic-language application, comprehensive tests are critical to keeping the project’s quality high and the developer’s sanity strong. So testing has to be a part of any serious effort with Oak.

Unfortunately, as soon as I start talking about testing, I start getting into several areas of discussion (unit tests, behavior tests, integration tests, Test-Driven Development and so on) that could easily consume another half-dozen magazine issues on their own, and I don’t want to crack that Pandora’s box here. Whatever your testing methodology or preference, suffice it to say that you must have some kind of testing presence in an Oak application (or any application, but the need is much higher in any dynamically typed environment), however you choose to test.

Meanwhile, the AddComment method is still missing.

Comment Away

In this particular case, when the user types a comment into the view, it POSTs to the HomeController Comments method, which looks like so:

[HttpPost]
public ActionResult Comments(dynamic @params)
{
  dynamic blog = blogs.Single(@params.BlogId);
  blog.AddComment(@params);
  return RedirectToAction("Index");
}

As you can see, the controller is first obtaining the blog ID tucked away in the BlogId parameter coming from the form, then using it to find the corresponding blog entry via the Single method on the DynamicRepository, then calling blog.AddComment to store the comment. (Again, just to make the points, both “pro” and “con”: This code has been in place since the second part of this series, and I’m just now running into the fact that the AddComment method hasn’t existed until now.)

Defining this method is pretty straightforward; on the Blog class, add this method:

void AddComment(dynamic comment)
{
  // Ignore addition if the body is empty
  if (string.IsNullOrEmpty(comment.Body)) return;
  // Any dynamic property on this instance can be accessed
  // through the "_" property
  var commentToSave = _.NewComment(comment);
  comments.Insert(commentToSave);
}

The only real question mark in this method is the use of the underscore (_.NewComment(comment)), which is a placeholder for the “this” reference. The underscore has full awareness of the dynamic nature of this object, which the “this” reference wouldn’t; rather than having to worry about the differences, the underscore lets you use everything “this” would, plus more.

Notice how the dynamic nature of the system lets you be extremely frugal in the code. The form parameters are captured in a named bundle in “@params” coming in to the controller, and those are passed without unpacking any of them directly into Add­Comment, which in turn passes them into NewComment, which constructs a dynamic object out of them, and the resulting object just gets inserted into the comments DynamicRepository. Where do the names of the object’s properties come from? From the HTML form that originated all of this.

Wacky, huh? Almost feels like you’re being lazy or something.

Anyway, give it a run, and sure enough, now comments are being added in.

Validate Me

As written, though, the system has a major flaw (well, according to user requirements, anyway): It’s perfectly permissible for two blog entries to have the exact same title, and that’s not OK. (Readers might get confused as to which one to read, the one titled “LOL Kittehs” or the other one titled “LOL Kittehs.”) Thus, you need a way of enforcing some kind of uniqueness on the code, so users can’t accidentally put in duplicate-titled blog entries.

In a traditional Web framework, this would be a two-part job. First, the model object (Blog) would have to define some kind of “ask me if I’m valid” method, which I’ll call IsValid for lack of anything really original, and a definition of said validation within the object, which I’ll call Validates. And, as one might suspect from the way the Associates method worked to help define the link between Blog and Comment objects (meaning, it’s a predefined name for which Oak knows to look), the Validates method works in the same way—if an object defines a Validates method, then Oak will call the already-defined IsValid method on the object, which in turn will look for a Validates method and ask it for all the conditions that make this object valid.

In code, that looks like this:

IEnumerable<dynamic> Validates()
{
  // And define the association
  // For other examples of validations, check out the Oak wiki
  yield return new Uniqueness("Name", blogs);
}

Again, you see the use of a stream of objects that describe the validation requirements, handed back as an IEnumerable<dynamic> to the stream, generated through the use of the “yield return” facility of C#. And, as with the Schema class from last time, the way to extend this is to just tack on additional elements that are “yield returned,” like so:

IEnumerable<dynamic> Validates()
{
  // And define the association
  // For other examples of validations check out the Oak wiki
  yield return new Uniqueness("Name", blogs);
  yield return new Length("Name") { Minimum=10, Maximum=199 };
}

The Oak Wiki defines the full list and usage of validation objects, but some of the notable ones are:

  • Presence: A field is not optional and must be present on the object.
  • Acceptance: A field on the object must contain a particular value, such as a LegalDocument object containing a TypedOutAcceptance field in which the user typed the string “I Accept” in order to indicate he accepted the legal restrictions.
  • Exclusion: A field can’t include certain values.
  • Inclusion: A field must be one of a set of certain values.
  • Format: The general-purpose regular-expression (using the Microsoft .NET Framework Regex class) validation.
  • Numericality: Pretty much everything to do with numeric values, including marking a field as “integer-only,” greater-­than and less-than restrictions, or simple even/odd tests.
  • Conditional: The catch-all “escape hatch” for any validation not covered elsewhere—a field must satisfy a condition described using a lambda function.

The last one, Conditional, isn’t actually a validation type in and of itself, but a feature present on most (if not all) of the other validation types, and therefore deserves a little more explanation. Imagine an Order object, for orders in a traditional e-commerce system. For said systems, a credit card number is only necessary if the user wants to use a credit card for payment. Similarly, an address to which to ship the product is only necessary if the user purchased anything other than a digital download. These two contingencies are neatly expressed using two conditional validations, as shown in Figure 1.

Figure 1 Conditional Validation

public class Order : DynamicModel
{
  public Order()
  {
  }
  public IEnumerable<dynamic> Validates()
  {
    yield return new Presence("CardNumber") {
      If = d => d.PaidWithCard()
    };
    yield return new Presence("Address") {
      Unless = d => d.IsDigitalPurchase()
    };
  }
  public bool PaidWithCard()
  {
    // Could use This().PaymentType instead
    return _.PaymentType == "Card";
  }
  public bool IsDigitalPurchase()
  {
    // Could use This().ItemType instead
    return _.ItemType == "Digital";
  }
}

Each of the Conditional objects is making use of a property on the Presence object—along with a lambda that yields a true/false value—to indicate whether the Presence validates successfully. In the first case, Presence returns true (pass) if d.PaidWithCard, a local method that returns true if the PaymentType field equals “Card,” returns true. In the second case, Presence returns true unless isDigitalPurchase returns true, meaning that if it’s a digital item, no address is necessary.

All of these are ready for use with any Oak DynamicModel-derived object, and, as noted in the prior column (msdn.microsoft.com/magazine/dn519929) and in the introduction of this one, the DynamicModel-­derived object needn’t explicitly define the fields that these validations reference. Should these validations not be sufficient to the task, by the way, these are all defined in the Validations.cs file inside the Oak folder of the scaffolded project. It’s pretty straightforward to define a new one if desired: Just inherit from Oak.Validation and define at minimum a Validate method that returns true/false. The Exclusion validation, for example, is this:

public class Exclusion : Validation
{
  public Exclusion(string property)
    : base(property)
  {
  }
  public dynamic[] In { get; set; }
  public bool Validate(dynamic entity)
  {
    return !In.Contains(PropertyValueIn(entity) as object);
  }
}

The In property in this code is the field in which the excluded values are stored; beyond that, this is pretty straightforward. If a descriptive error message needs to be included, Validation provides a base property, ErrorMessage, in which a descriptive message can be stored for use if validation fails.

(For those who are curious about the “associations” from the database discussions last time, these are defined in Association.cs in the same folder, derive from Oak.Association, and—as one might expect—are a little bit trickier to explain. Fortunately, Oak has most of the traditional relational associations already defined, so there shouldn’t be much need to customize here.)

Pieces of Oak

Sometimes parts of a library seem really cool, but obstacles stand in the way of adopting the whole thing, and you just wish you could rip out a small part of it and keep going. While it’s usually better to use Oak as a whole, it does support the idea of ripping out bits of it (such as the dynamic database portions, or perhaps just the dynamic object portions, called Gemini, which I covered in the August 2013 issue, at msdn.microsoft.com/magazine/dn342877) and using them standalone, without the rest of the system. The Oak GitHub page on the subject (bit.ly/1cjGuou) has the NuGet packages for each of the standalone Oak parts, reproduced here (as of this writing) for your convenience:

  • install-package oak: This is the full Oak suite, it includes MVC model binders, schema generation, the Oak DynamicModel and supporting classes, an altered version of Massive (DynamicRepository), and the Oak core dynamic construct Gemini.
  • install-package oak-json: This is the part of Oak with regard to JSON serialization (can be used in REST APIs).
  • install-package cambium: This is the part of Oak that excludes the MVC-specific components and excludes schema generation. Cambium includes the Oak DynamicDb, DynamicModel, an altered version of Massive (Dynamic­Repository) and the Oak core dynamic construct Gemini.
  • install-package seed: This is the schema generation of Oak. This NuGet package also includes the altered version of Massive (used to insert sample data). It doesn’t contain any of the MVC model binders, or the Oak DynamicModel or supporting classes.
  • install-package gemini: This will install just the core dynamic construct upon which all the dynamic goodness in Oak is built.

Before trying out any of them in pieces, I’d suggest trying the whole experience to get a feel for how each of them fit into the larger picture.

Benefits, Cost and Pain

As might be inferred from these four columns, there are definite benefits to being able to just “wing it” and work with a more dynamically typed system. Without question, costs and pain will raise their ugly heads in such a system (particularly for the unwary, and those unused to writing tests), but even those who are the most diehard statically typed bigots can learn some valuable ideas from a system like Oak. More important, Oak can be a hugely valuable tool for prototyping the early development of a system, when the object model is still highly mutable and undefined. Best of all, thanks to the underlying platform of Oak (that is, .NET), it becomes quite feasible to suggest building an MVC app in Oak in the early stages, then slowly flipping parts of it over to a more statically typed (and, thus, compiler-checked and compiler-enforced) approach as the details of the application get more tightly locked down.

Personally speaking, without a doubt, Oak is a cool little project. To my mind, this is one of those times when a whole lot of interesting functionality and ideas come out of a pretty small (relatively speaking) package. Oak definitely goes into my personal toolbox of tricks.

Happy coding!


Ted Neward is the principal of Neward & Associates LLC. He has written more than 100 articles and authored and coauthored a dozen books, including “Professional F# 2.0” (Wrox, 2010). He’s an F# MVP and speaks at conferences around the world. He consults and mentors regularly—reach him at ted@tedneward.com if you’re interested in having him come work with your team, or read his blog at blogs.tedneward.com.

Thanks to the following technical expert for reviewing this article: Amir Rajan (Oak project creator)
Amir Rajan is the creator of Oak. He's an active member of the development community and has expertise in ASP.NET MVC, HTML5, REST architectures, Ruby, JavaScript/CoffeeScript, NodeJS, iOS/ObjectiveC and F#. Rajan is a true polyglot with an unwavering passion for software. He's on Twitter at @amirrajan and on the Web at github.com/amirrajan, amirrajan.net and improvingenterprises.com.