Introduction
TempHire is
a reference application that has been designed from the ground up to scale to
the needs of medium-to-large business applications. It demonstrates a range of architectural
and design patterns, including repository patterns, Model-View-ViewModel (MVVM)
presentation style, view composition, multi-screen navigation, data-binding, reusable
UI components, validation, and multiple EntityManagers for sandbox editing and
cache management.
Being a
reference app, we’ve kept TempHire manageable and limited its scope to
something that highlights our enterprise design decisions without too many
distractions. TempHire demonstrates a single Resource Management module in
action, but you can see how additional modules (Scheduling, Customer Management,
etc., etc.) could easily be built on its framework.
Challenge
Enterprise applications
(line of business applications or LOBs) typically have task-oriented UIs and
complex, cross-functional, workflows. They need multiple views and require
considerable navigation. Given only a few screens, screen composition,
decomposition, and data-binding to complex data models can get out of hand in a
hurry.
Likewise, LOBs
need to able to read, modify, and create data, so determining how to shuttle
data back and forth between the UI and the back-end becomes yet another
challenge. There’s a lot of tedious code involved in turning all that raw data
into business objects and moving them to and from the client.
Putting all of
the pieces together is enough of a challenge on traditional, relatively static,
desktop clients; but more and more frequently, product requirements demand that
these apps go cross-platform and work on desktops, tablets, and multiple mobile
devices.
How do you
design and write LOB apps that can handle real-world complexity? How do you
build apps that can be easily maintained and extended over multiple years? How
do you go cross-platform without hiring an army of developers to rewrite your
code for multiple clients?
Solution
TempHire is
designed to be a completely modular single-page application (SPA). It’s written
in JavaScript, so it works on the platforms your customers use today—and will
still be using tomorrow.
TempHire
reduces complexity by leveraging frameworks like Durandal
for presentation and libraries like Breeze
for data management, so developers can focus on solving business problems rather
than the plumbing and wiring.
Even better,
through the use of proven architecture and design patterns, multiple developers
can work independently on specific views, models, and workflows without
impacting other modules.
TempHire under the hood
So what
exactly does an enterprise JavaScript app look like from the inside? TempHire
is one way to do it—a way we’ve had success with and are happy to share with
you.
TempHire is
composed of a client side app (JavaScript, CSS, HTML, etc.), a domain model
(entities, and business logic) and various server side components (services,
controllers, etc.).
Domain model
The DomainModel
is the main model for all of the application
data. TempHire’s domain model contains all of its entity classes, an entity
base class, and a DbContext file.
Entity classes
Let’s look
at AddressType as an example of one of Temphire’s entity classes. It’s a Code
First class that has four properties.
EntityBase
TempHire
uses a base class that all the entities, directly or indirectly, inherit from
(EntityBase.cs). The nice thing about Code First is that TempHire can add
common functionalities to the base class that will be applied to all of the
entities in the domain model. Because these functions are in the base class,
TempHire doesn’t need to add them to derived classes. Everything is
inheritable.
You can see
this in action by the way that TempHire handles concurrency checking. It’s
located in the base class and is inherited by every entity.
DbContext
TempHireDbContext
demonstrates how we map TempHire’s domain model to a database using
EntityFramework Code First. TempHire tells EF what its entitysets are, and sets
a few initialization strategies (e.g. dropcreatedatabaseifmodelchanges
).
To be very clear, we’ve built TempHire as a demo app ... and in this context,
this makes sense. Don’t drop your database in a production application!
Projections
Temphire
uses projections and DTOs where applicable to improve performance and to move
complex queries to the server, where implementing them in LINQ is a lot easier.
You can see this in action on the master details screen:
Frequently
you’ll see grids like this populated by entities, but we don’t do that here. Instead,
this grid uses a projection query that cherry picks the information from an
object graph, condenses it, and sends it down the wire. Projections are a simple
way to enhance performance, and your customers who are connecting via an EDGE
network will be happy you did.
TempHire app
With the
domain model behind us, let’s take a look inside the app itself.
App
The App folder contains the core components of the TempHire
client: Durandal, Client Services, ViewModel code, the HTML Views, and main.js,
the script that bundles the app’s scripts into a single package.
We’re assuming you’re familiar with the basics, so the most
interesting components here are likely App/Durandal and App/ Services.
Durandal
Durandal, Rob Eisenberg’s excellent SPA framework, leverages
Knockout and Require. Durandal takes care of the front-end plumbing and makes
screen composition and management fast and easy. Even better, Durandal promotes
architecture practices that will positively impact scalability and long term
maintenance. Long story short, Durandal saves a ton of time and hassle in
regards to architecturally sound front-end development.
Services
Services contains the JavaScript that powers TempHire’s
primary services … most of which revolve around Temphire’s reliance on the Unit
of Work (UOW) pattern.
Entitymangerprovider.js offers a CreateManager method for
TempHire to call whenever it needs a new EntityManager instance—something it
does frequently as each UOW must spin up a new EntityManager. Logger.js takes
care of TempHire’s logging functions, Repository.js is responsible for the
configuration of UOW Repositories, and Unitofwork.js is responsible for the
configuration of the UOW themselves.
App_Start
App_Start contains BreezeWebApiConfig.cs, BundleConfig.cs,
and InfrastructureConfig.cs. These files run at the beginning of the server
launch sequence and register their applicable routes. BreezeWebApiConfig routes
Breeze client requests to the Breeze controller, and InfrastructureConfig
registers the resource bundles via the BundleConfig
helper class. Additional
infrastructure configuration can be added here later.
Content
All of TempHire’s content files (CSS and images) are stored
in the appropriately named Content folder. This is a good time to mention that
TempHire uses Twitter Bootstrap,
an excellent template for quickly standing up a modern front-end.
HTML, CSS, UI elements, responsivity—yeah, Bootstrap takes
care of all of that.
Controllers
DefaultController.cs
The default controller is responsible for delivering the common metadata. Query
and Save logic is to the respective module controllers.
LookupBundle.cs
The LookupBundle is a DTO used to ship global read-only entities such as lookup
data to the client in one shot. A client requests this data once at the
beginning and holds it in a global cache. Every EntityManager
when first
created is pre-seeded with this global lookup data.
ResourceMgtController.cs
The ResourcMgtController
defines the query and save endpoints for the resource
management module. Each module gets its own controller in order to keep their
size manageable and combine related functionality in one place.
Much as like we did client-side, the server-side also uses
the unit of work pattern to structure the query and save logic and keep it
external to the controllers. This way the controllers stay small enough and the
business logic is encapsulated in the corresponding server-side unit of work.
Scripts
Temphire is
powered by eight JavaScript libraries. If you’re new to JavaScript and are
concerned by seeing so many libraries, please stop reading this article and read
to John Papa’s Why all
those JavaScript libraries. Feel better now? The libraries that make
TempHire tick include:
Bootstrap
adds front-end pizazz with a variety of widgets, transitions, buttons, etc. It
should go without saying that they all work seamlessly with the Twitter
Bootstrap CSS (See Content). The various GUI elements are documented at twitter.github.io.
Breeze
excels at data management and takes care of the Model –the M in MVVM. Breeze
queries, saves, and manages all data interactions between client and server. Breeze
EntityManagers make writing TempHire’s Unit of Work patterns
considerably easier.
Breeze automatically creates JavaScript model objects
(entities) that match the shape of the data coming from the remote service. It
adds business rules and infrastructure that support validation, change
tracking, and navigation to related entities. Breeze navigation properties
automate traversal of the object graphs that are implicit in a relational model
so you can walk the graph, from a customer to its orders, and from an order to
its line items. Breeze tracks users’ changes and validates them with rules,
some of which may have been propagated to the client from the server.
If you store data in a database, query and save data as
complex object graphs, and share graphs across multiple views—and want to do it
in JavaScript—there’s no better way than with Breeze.
jQuery is a
dependency for some of TempHire’s libraries and templates. Bootstrap, Breeze, Durandal,
and Sammy rely on one bit of jQuery or another.
Knockout manages
the data-binding and dependency tracking for the presentation layer—the ViewModel—the
VM in MVVM. Even better, it is intimately tied to Require and Sammy via the
Durandal framework, making much of the front-end wiring easier.
Moment is our
go-to library when working with date and time (parsing, validating,
manipulating, and formatting) in JavaScript.
q
assists in managing asynchronous operations through CommonJs promises.
Sammy is a small,
yet powerful, framework for building SPAs like TempHire. (Sammy refers to them
as single-page AJAX applications, but SPAJAX is a bit of a mouthful.) TempHire
uses Sammy primarily for its navigation and routing functionality.
Toastr
displays process and error notifications in "toast" windows that
float up from the lower right to let you know what TempHire is doing at any
given time.
Services
All of TempHire’s
persistence ignorance is built into the server-side services using Unit of Work
(UOW) patterns.
Unit of Work
The UOW is a
design pattern that encapsulates anything from simple tasks to complex workflows.
The UOW can be short or long lived, may involve retrieving data, modifying
data, creating new data, performing business logic, checking business rules,
and saving or rolling back changes.
An EntityManger
is spun up for each UOW and takes care of the configuration, authentication,
and connection details, while the UOW’s Repository handles the business logic
that governs access to a specific type of entity.
UOWs make it
possible to highly optimize the fetching strategy for a given entity type.
i.e. A Repository
for a static type such as Color can be optimized to load all colors on
the first request and serve future requests directly from the cache instead of
making additional trips to the server.
UOWs can be
shared between ViewModels if different parts of the UI work with the same data,
but each UOW remains a unique sandbox.
TempHire
uses UOWs as transaction boundaries—each with customized responsibilities that lead
to an organized codebase that’s easier to maintain and improve over time.
What about the back-end?
TempHire's is
an ASP.NET Web Application. The server hosts all the client-side assets as well
as an ASP.NET MVC4 Web API service that queries and saves to a SQL Server
database with the help of an Entity Framework Code First model. We used ASP.NET
because it’s quick and effective for enterprise developers familiar with the
Microsoft stack. It’s also helpful that Breeze ships with components that ease
development of Web API and Entity Framework back-ends.
If you
prefer a Rails or Java backend, or NoSQL database, you’re ok too. TempHire is a
JavaScript app and can been configured to run on almost any server stack that
can deliver web assets and data services.
Learn more
In addition
to the TempHire sample, you can find more information about building SPAs at www.breezejs.com, including:
Need more
help?
We'll work
with your team to build a customized
training course that's tailored to the needs of your team and project.
About
Breeze is
actively developed by IdeaBlade. Follow @BreezeJS
on Twitter and Like us on
Facebook.