< Research and Development

Design Patterns

To solve the complex software engineering we faced when developing our Proof of Concept, we employed several different standard design patterns. These design patterns helped us achieve better structured code for future readability and maintenance. Click the buttons below to jump to the corresponding section.

1. Component Level 2. Angular Application

Component Level Design Patterns

Although design patterns technically describe classes in an object oriented system, we applied them on a macro-level to entire components in the architecture of our system.

Flask application

The entire Flask application serves as a mediator that interprets all data operation requests received from the Angular application and calls the appropriate correct Celery function. The mediator pattern helped us achieve decouple the WebSocket and HTTP API requests from their specific implementation details in the backend, allowing us to easily to modify exactly how a request is handled in the backend.

dcs package

When we decided to use the pandas data science library for data representation and manipulation in the backend, we did not want our code to be too interdependent on the pandas librari. Therefore, we developed a separate Python package called dcs. Every request in the backend ultimately gets performed by functions defined in the dcs Python package we developed. This emulates the façade design pattern, which abstracted away the implementation details of data operations and provided a simplified interface to the pandas library, therefore achieving a lower level of coupling within the backend by lowering the dependence on pandas.


^ Back to Top


Angular Application Design Patterns

Because we took care to avoid a monolithic architecture by modularizing the backend of our system, the only complex singular component in our application that demanded an object-oriented approach was the Angular application.

Model-View-Controller (MVC)

Although not technically a design pattern, Angular as a web application enforces the MVC architecture to achieve separation of concerns within classes. A Model’s only concern is to encapsulate data while Views are defined as HTML files whose only concern is to reflect the model. A Controller’s job is to manage the Model and View and ensure that the Model gets reflected in the View, and that UI events received by the View manipulate the Model’s state accordingly.

Dependency Injection

AngularJS enforces the dependency injection design pattern for resolving class dependencies. In dependency injection, classes delegate the responsibility of initializing its dependencies to an external object, allowing the system to follow the dependency inversion principle. This achieved a lower level of coupling between classes and their dependencies, and played a critical role in improving the testability of our Angular app, allowing us to define mock dependencies for isolating the object under test.

Publish-Subscribe

We used the publisher-subscriber pattern to set up event listeners in the Angular application. The publish-subscribe pattern allowed us to dynamically register objects at runtime as subscribers/listeners to messages which get published by other objects. This messaging pattern was implemented to avoid using Angulars $watch mechanism in order to improved performance and customize behavior. The pattern was used primarily in the providers of our Angular application, which request and receive messages pushed from the backend. The publish-subscribe pattern achieves decoupling between message senders and message receives.

Singleton

To encapsulate global state and expose an interface for commonly used functions, we defined several singletons in our application through Angular’s provider mechanism, which lazily initializes singletons before injecting them into dependent objects. All providers we defined act as singletons, and they are responsible for tasks such as encapsulating the application session and abstracting the WebSocket API.

Proxy

One of the singletons in our application also acts as a proxy that performs caching on statistical analyses that are returned from the backend in order to improve performance.


^ Back to Top