As mentioned in Chapter 1, Building a Single-Page Site Using Backbone, Syapse (http://www.syapse.com) is a Backbone-powered web application for requesting and providing precision medicine results. Syapse's customers are laboratories and hospitals that use genetic sequencing to profile patients with serious diseases like cancer. Once sequenced, these genetic profiles can be combined with large bodies of research to determine the best treatments and dosages for a given patient based on the patient's own DNA.
Let's take a look at how Syapse was put together.
Syapse's client-side code is organized using Require.js (see Dependency management with RequireJS in Chapter 11, (Not) Re-Inventing the Wheel: Utilizing Third-Party Libraries). Every module is either a class, a singleton instance (for utility libraries), or a function (for routes). Syapse has two different sites, one for laboratories and the other for clinics, so we use RequireJS to compile separate JavaScript files for each site.
Each of these files has its own Backbone Router
, allowing each site to have a completely distinct set of URLs and pages (see Multiple routers in Chapter 6,
Creating Client-Side Pages with Routers). These Router
classes form the top of the RequireJS dependency tree, bringing in (or depending on) all of the site's routes. These route modules then bring in the site's Views
classes, which in turn bring in the site's Model
and Collection
classes.
There are four "base" classes that every other class in the application inherits from. These base classes are based on the BackSupport classes (see Making life easier with BackSupport in Chapter 11, (Not) Re-Inventing the Wheel: Utilizing Third-Party Libraries), and are used to define new features that are Syapse-specific. For instance, since Syapse uses the Handlebars templating library, the base View
class includes the logic for rendering Handlebars templates (see Templating with Handlebars in Chapter 11, (Not) Re-Inventing the Wheel: Utilizing Third-Party Libraries).
Syapse uses the Page View
pattern (see Page views in Chapter 5, Adding and Modifying Elements With Views) with one base Page View
class for the laboratory interface and one for the clinic interface. These render all of the parts of the site that are shared between pages, such as the navigation menu, and both of these Page View
patterns share a common base View
class, allowing them to reuse generic page-rendering logic that is common to both sites.
Pages in the Syapse laboratory site are divided into three sections, each with their own View
class: a left navigation section, a header area, and a main content area. Each of these can optionally be overwritten when the page is instantiated, letting each route modify only its unique section(s). For instance, most routes don't change the left navigation bar, so when these routes instantiate the page View
class, they simply rely on the default navigation bar of this View
class.
Each of the subclasses of View
handles the rendering of its part of the page. Because Syapse relies on The combined approach (see Chapter 5, Adding and Modifying Elements with Views) to do its rendering, these View
classes use a combination of Handlebars templates and other child View
classes to generate their content. For particularly complex pages, this can result in not just child View
classes but also grandchild, great grandchild, and sometimes, even great-great grandchild View
classes. Whenever possible, Syapse uses multiple smaller View
classes rather than one large one, to keep the logic for each View
class as simple as possible.
For consistency, all of the render methods in these View
classes return this. Further, for consistency, each View
class is designed to be re-renderable, so that it can easily listen and respond to change events in its Model
classes (see Other render considerations in Chapter 5, Adding and Modifying Elements with Views).
On the server-side, Syapse uses Python and the Django REST Framework library to power all of its APIs, and while this gives the server team a great deal of control over the API, they are still somewhat limited by the library and can't always make APIs that return ideal Backbone JSON. Because of this many of Syapse's Model
and Collection
classes make use of parse
and toJSON
method overrides to extract or send back the correct JSON to/from the API (see Fetching data from the server and Saving data to the server in Chapter 3, Accessing Server Data with Models).
Sometimes, Syapse's APIs return not just the data for a given Model
or Collection
class but also supplemental information. For instance, an API that returns a patient Model
class might include the ID of that patient's doctor, but since the end user wants to see a name instead of an ID, the API response also includes a separate map of IDs to names. To keep track of this supplemental information, Syapse relies on a global pub/sub system (see Publish/Subscribe in Chapter 7, Fitting Square Pegs in Round Holes: Advanced Backbone Techniques). Whenever a Model
class parses such supplemental information during a fetch, it triggers a special supplemental information" event with this information as an extra argument. This event is then listened for by one or more site-wide Collection
caches, which aggregate the supplemental information and make it available for the View
classes.
All of Syapse's code is tested using Selenium for acceptance testing and Mocha/Sinon for unit testing (see Testing? In JavaScript? and Selenium in Chapter 10, Keeping the Bugs Out: How to Test a Backbone Application). By using expressive test names and the BDD test output style (see TDD versus BDD: What's the difference? in Chapter 10, Keeping the Bugs Out: How to Test a Backbone Application), we ensure that Syapse's test output is very specific and looks like the following:
For documentation, Syapse relies primarily on inline documentation, using JSDoc annotations without actually rendering documentation pages (see The robust documentation approach in Chapter 9, What Was I Thinking? Documenting Backbone Code). However, Syapse also has a customer-facing JavaScript API, which is considerably more heavily documented than both generated JSDoc API pages and a Docco-based tutorial.
35.170.81.33