Blog

Architecture: What is it and why do you want one?

An architecture is essentially a set of design constraints imposed on an IT development project.

You want architecture because unconstrained design leads to impedance mismatches among the various pieces of a system due to logical or physical incompatibilities among software components developed by different team members or third parties.

The result of no architecture is software that takes longer, costs more to build or is more expensive to operate once it’s deployed.

Impedance mismatches can manifest in a variety of ways:

  • Model – Multiple, possibly inconsistent object definitions for the same logical entity
  • API – Incompatible arguments or return results required or produced by libraries
  • Performance – Inability of data sources to provide data as fast as required
  • Locks – Contention resulting from different components having different expectations for how resources should be shared
  • Transactions – Improperly serialized updates resulting in data being lost or overwritten with stale values
  • Responsibility – Functionality needlessly duplicated or incorrectly assumed to be provided elsewhere
  • Recovery – Components in the event of failure not coordinating properly to minimize downtime or data loss
  • Operational – Software too difficult to modify in response to anticipated future needs

An architecture is sufficiently defined when you can turn a developer loose on developing some piece of functionality and if he or she obeys all the established design constraints.

An established architecture will ensure a minimal possibility of creating software that produces any of the above problems. If you’re conceptually bothered by being constrained, preferring instead to program in wide open spaces with the wind blowing in your hair, perhaps you would prefer to instead think of architecture a form of freedom — the freedom of choice. Once defined, an architecture frees developers from having to make (possibly incompatible) choices for how to implement an application’s functionality and instead devote most of their time to implementing functional requirements while minimizing the time spent hacking together glue to integrate with the rest of the team’s code.

Architecture: What is it and why do you want one?

Here’s a very high-level breakdown of a typical ERIA BackendService:

In any non-trivial enterprise application development project, multiple developers will be working in tandem and in a RIA project where the client and server platforms do not even use the same programming language. It is natural here that developers will be divided into front-end and back-end teams.

In order to reduce dependencies between client and server code development and allow the teams to work in relative independence on their respective components, it makes sense to explicitly define an API that will provide the linkage between the client and server code. The BackendService is typically implemented using a webservice-type container. Tomcat and associated plugins, for example, provide a framework for authorizing users, managing session data, and communicating over web protocols such as REST.

UserSession

As with most traditional web applications, we require a container that maintains session state for each logged in user. Unless application users are anonymous, the session state will at a minimum contain user identity information required for access control. For many applications, code can be simplified by maintaining other session-specific information on the server. For example, the current contents of the user’s shopping cart.

UserIdentity

In most applications, we require user identity information in order to be able to complete requests received from a client. For example, when a user requests information for “my account”, the server must need to somehow know which account to access. It is typically not an option to supply the account number as part of the request; since the client could be running a hacked application that allows the user to specify an arbitrary account number. When the user authenticates with the server, the server must associate the authorized user’s identity with the session and check each subsequent request against the identity information in order to perform the requisite access control.

UserIdentity is typically implemented with role-based security frameworks such as JEE security implementations riding on LDAP or some other user directory store.

DomainObject

DomainObjects are instances of classes that directly model some aspect of our problem domain, such as Customers, Invoices, and Products. These objects are mostly created from input received from the client, by being retrieved from a database or some external source and additionally provide the non-UI-specific logic comprising our application. If we do our jobs right, most of the custom code we write on the backend will be domain-specific, having delegated most of the non-domain-specific plumbing to third-party frameworks.

PersistenceManager

The PersistenceManager caches previously retrieved data and collects updates triggered by the client until a logical transaction is completed and can be committed to a database or external system.

BackEndServiceAPI

Clients access the BackEndService via a library that provides a client-code-friendly interface. This BackEndServiceAPI is often no more than a wrapper that exposes the BackEndService interface in the client’s native language and does little more than marshal arguments as necessary to call whatever remoting framework is being used for backend communication, and set up whatever callbacks are needed in cases where results are returned asynchronously.

The BackEndServiceAPI would usually be defined as an interface for which a mock implementation can be used as a stand-in so that the front-end team has the option of proceeding with development ahead of the back-end implementation being complete.

DomainDTO

In a typical RIA, we cannot actually return full-blown objects from the server to the client or vice versa. Instead, we can only transmit an object’s primitive property values. For example, if the client requests a particular Customer, the server does not return an actual instance of a DomainObject. Instead, it returns a set of values such as name, address, and account number. While it’s possible to construct an actual DomainObject instance from these returned values, it is often unnecessary. This is because an RIA in many cases is merely providing for the display and editing of such primitive values, delegating any requisite business logic back to the server-based DomainObjects. DomainDTO’s are objects that provide holders for these

DomainDTO’s are objects that provide holders for these values, but don’t necessarily provide any “behavior” in the form of methods on the objects. It is of course also common to selectively replicate some DomainObject logic on the client, especially simple field edits, and in some cases we might even replicate complex logic on the client, so we’re using the term DTO loosely here.

CacheManager

With a thin client, client-side state does not usually consist of any more than the contents of some html form or table. Each new view usually requires a round-trip to the server to retrieve both the definition of the view (ie, an html page), and the data presented within it. Just changing the sort sequence of the rows in a table require re-retrieving a fully formatted table of data from a server. One of the big advantages in a RIA is that we can provide a much more interactive and responsive user experience by not requiring the constant back-and-forth of data and markup with the server.

Instead we can retrieve (possibly large amounts of) data just once, display it in a variety of ways, allow the user to edit it, and send updates to the server only after a transaction is logically complete.The CacheManager keeps track of what we’ve already retrieved from the server so that we don’t incur unnecessary overhead of re-retrieving the same data, and tracks what objects are changed (“dirty”) and require transmission back to the server. The sophistication of CacheManagers can vary greatly from one application to another, consisting of little more than hash tables of objects by type, or as much as client-side relational databases.

ViewComponent

The view components are the widgets that provide for the display and editing data, usually DomainDTO’s retrieved from the local cache. By ViewComponents, we don’t mean low-level UI components like buttons and textfields, but semantically rich composite components such as for example a Customer Creation Form or an Order History Table.

EventBus

RIA platforms are event-driven user interface frameworks. ViewComponents emit and respond to asynchronous notifications such as “User Wants to Quit” or “User Has Updated His Credit Card Info”. While such event-driven models are ideally suited to coordinating the asynchronous update and display of data across possibly multiple views, event-driven programs can degenerate into a tangle of interdependencies among components dispatching and listening for each other’s events. An EventBus organizes event handling around a hub-and-spoke where events are logically broadcast throughout the application. In this way, brittle point-to-point connections are replaced by a robust, centralized switchboard for application events.

An EventBus organizes event handling around a hub-and-spoke where events are logically broadcast throughout the application. In this way, brittle point-to-point connections are replaced by a robust, centralized switchboard for application events.

Application

The Application is “everything else”. It’s the code necessary to integrate the BackEndAPI, the ViewComponents, and the CacheManager into the functioning whole experienced by the user. The Application, for example, binds particular views to particular DTO’s and invokes particular BackEndAPI methods in response to user interactions.

Unfortunately, the above does not lay out all of the architecture. It only frames the questions more clearly. Chiefly:

  • Whether to locate logic on the client or server?
  • How much data to cache locally on the client?
  • When should data be transmitted from the client to the server?
  • When should data be persisted to a database?
  • How should view components be made aware of updates to what is being displayed?
  • What is the right level of granularity for remote operations?

Having diligently studied the above description, you may be chomping at the bit to put the above principles to work and begin building your next RIA. To read more about the different enterprise architecture methodologies please see the article by Microsoft.

Can I just go build my application now?

Have any questions about nearshoring or onshoring your software development? Don’t hesitate to contact us.

Ready to be Unstoppable? Partner with Gorilla Logic, and you can be.

TALK TO OUR SALES TEAM