Chapter 7. Implementing the Business Logic

Over the past several years, the knowledge base around JavaScript has matured tremendously. Web applications appeared on the scene with more and more functionality as JavaScript libraries helped to accelerate the move from server-based applications to large client-based applications.

This trend of moving functionality from the server to client was due to many things, but mostly because of the advancements in technology that provided the same speed and processing power as our desktops to mobile devices. This new power beckoned developers, urging them to move more and more away from the server to the client. We have seen JavaScript at the core of this movement. Developers have created cross compilers and emulators that allow game engines and virtual machines to run in the browser, providing the same, if not better performance, than their original platforms.

This same shift has seen the appearance of unhosted web applications, applications that no longer rely on servers to process logic, but leverage cloud-based services to perform authentication and data access, and implement business logic as part of the web application. These unhosted web applications can run on any platform, allowing you to choose where your data lives and help keep your data private and away from app providers. They are also cheaper to host, easier to mirror, and provide near infinite scalability.

This chapter looks at the various ways we can implement our business logic in the services we create. It also explains some of the services used in our application to implement complex rule-based calculations and handle user process flow based on a finite state machine.

Encapsulating business logic in models

In Chapter 2, Designing Services, and Chapter 5, Data Management, we looked at how to create model services in our application using the value provider and a standard JavaScript constructor definition. This allowed us to inject the model into our controllers, directives, and services the same way we would in any other AngularJS component. We also discussed how to use prototypal inheritance to define the business logic code associated with the model. We also covered a generic translation service to allow us to transform the plain JSON objects received from external data services into our model objects.

This concept of keeping the business logic that operates on an object with the object is a standard object-oriented programming principle that many object-oriented languages provide as part of the class definition. This is accomplished in JavaScript by redefining the object's prototype as follows:

var Fermentable = function() {
  var self = this;
  self.Name = '';
  self.Type = ''; // can be "Grain", "Sugar", "Extract", 
                  // "Dry Extract" or "Adjunct"
  self.Amount = 0.0;
  self.Yeild = 0.0; // percent
  self.Color = 0.0; // Lovibond units (SRM)
  self.AddAfterBoil = false;
  self.Origin = '';
  self.Supplier = '';
  self.Notes = '';
  self.CoarseFineDiff = 0.0; // percent
  self.Moisture = 0.0; // percent
  self.DiastaticPower = 0.0; // in lintner units
  self.Protein = 0.0; // percent
  self.MaxInBatch = 0.0; // percent
  self.RecommendMash = false;
  self.IBUGalPerPound = 0.0;
  self.DisplayAmount = '';
  self.Potential = 0.0;
  self.DisplayColor = 0.0;
  self.ExtractSubstitute = '';
};

Fermentable.prototype = {
  /**
   * calculates the gravity per pound for the fermentable
   * @param brewHouseEfficiency - the estimated brew house 
   * efficiency
   * @returns {number} - potential extract per pound for the 
   * fermentable
   */
  gravityPerPound: function(batchType, brewHouseEfficiency){
    var result = ((this.Potential - 1) * 1000.0);

    switch(batchType)
    {
      case "All Grain":
        result = result * brewHouseEfficiency;
        break;
      case "Partial Mash":
        result = result * 0.33;
        break;
      case "Extract":
        break;
    }

    return result;
  },
  /**
   * calculates the gravity for the ingredient
   * @param brewHouseEfficiency - the estimated brew house 
   * efficiency
   * @returns {number} - returns the total potential extract for 
   * the fermentable
   */
  ingredientGravity: function(batchType, brewHouseEfficiency){
    return this.Amount * (this.gravityPerPound(batchType, 
             brewHouseEfficiency) / 1000);
  },

  /**
   * calculates the gravity points for a given recipe
   * @param batchVolume - total pre boil volume
   * @param brewHouseEfficiency - the estimated brew house 
   * efficiency
   * @returns {number} - returns the total gravity points for the 
   * fermentable
   */
  gravityPoints: function(batchType, batchVolume, 
    brewHouseEfficiency){
    return (this.ingredientGravity(batchType, brewHouseEfficiency) 
             / batchVolume);
  },

  /**
   * calculates the color the fermentable will contribute to a 
   * batch of beer based on the amount of the feremntable
   * fermentable used in the recipe
   * @returns {number} - the srm color value for the fermentable
   */
  srm: function(){
    return parseFloat(this.Amount) * parseFloat(this.Color);
  },

  /**
   * calculates the color the fermentable will contribute to a 
   * batch of beer based on the pre-boil volume of the recipe
   * @param batchVolume - total pre-boil volume
   * @returns {number} - the srm color value for the fermentable
   */
  colorPoints: function(batchVolume){
    return this.srm() / batchVolume;
  }
};

This definition allows us to create a new instance of the object and invoke the object methods as follows:

var grain = new Fermentable();
grain.Amount = 5;
grain.Color = 3;
grain.Potential = 1.039;

var gravityPoints = grain.gravityPoints('All Grain', 10, 0.65);

The advantage of using prototypal inheritance is that it allows us to define the business logic as part of the model object. It also allows logic to be easily invoked by calling the function associated with the object's prototype. This makes the code much easier to read and reduces the need to create additional functions that operate on the object. The main disadvantage is that the business logic for an application can end up being spread across your entire application. You might have some business logic in the models and other business logic in services or libraries; this can make it tough to maintain as the application gets larger.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.88.110