Introducing Gravity framework

Julian Molina
Brainz Engineering
Published in
6 min readFeb 14, 2017

--

There is always a moment in the life of a programmer when we ask ourselves what is the best framework or what is more suitable tool to do best our job. We’ve faced these questions many times no matter what technology or programming language we want to use. For example, after mulling over technologies to implement our web frontends, we finally decided to use Typescript, a superset of Javascript created by Microsoft which provides more features and functionality, making us more productive than using plain Javascript.

We also choose this language because it allows us to organize better our projects using namespaces, in a similar fashion as we do in Java, C# or PHP. The ability to use interfaces, optional static typing and class-based object-oriented programming were other characteristics that we fell in love with.

However, choosing a programming language does not necessarily imply that every technical decision made by the programmers in a team is automatically aligned with the other team members’ preferences. May be the case that a developer choose to follow different development decisions, coding standards, file structure, conventions and more.

Adopt an existing framework

Usually a common solution is to adopt an existing framework that give us structure and a well-defined development philosophy. Rapidly, we got on with the job of looking for the best framework that suits or needs. Carefully reviewing the available options in the market, we immediately found the most popular frameworks: ReactJS, Angular 2 y VUE, each of them having their own advantages and drawbacks.

An additional variable we had on the table was that we wanted to find something similar to the ideas and presets we already had using backend frameworks. For us, being backend developers mostly, was easy to figure out that many Javascript frameworks have been conceived based on quite different ideas from the ones we already knew using backend frameworks. This isn’t surprising at all, backend and frontend are very different environments, and doesn’t make any sense try to adopt incompatible philosophies or force incongruous ideas to fit in a completely different environment. However, we knew that if we iterate enough over some of the ideas we had, we could end up with something that would naturally fit more with what we were looking for.

With this in mind and without further ado, we’re started to shape a javascript framework called Gravity.

Create a framework to solve your own needs

Needless to say we aren’t expecting to create something better in every aspect than existing mainstream solutions. It would be a huge work for us and probably something that we wouldn’t be able to achieve in the short term. However, we had in mind certain mandatory features that we were urged to have. To begin with, the new framework must require minimal dependencies and it should be very lightweight compared to other existing solutions. Additionally, we didn’t want to depend on command line utilities to perform tasks but having powerful abstractions to rely on. Personally, I was looking to start developing features as required, rather than build a huge amount of features just in case they will be needed in the feature.

Angular2 dependencies

Object-Oriented HTML

The idea for having object-oriented HTML came up for two reasons: on the one hand, unity the way of creating HTML via Javascript reducing the need of using DOM functionality directly, overcoming browser incompatibilities and in the other hand take advantage of the abstractions that TypeScript provide us:

// DIV creation
let div = new View.Div();
div.class("container");
div.attr("id", "5");

// Fluent interface
let str = new View.Strong();
str.class("strong-to-bold")
.click(element => { console.log("text click") })
.append("Hello World");

div.append(str);

Despite being quite similar to using DOM directly, it allows us to use a fluent interface and encapsulate the many inner workings of HTML and Javascript.

let options = [
{
"id" : 1,
"name" : "Andrew",
"last" : "Hardy"
},
{
"id" : 2,
"name" : "Unit",
"last" : "R2"
}
];

let select = new Select();
select.build(options, ["id", "name"]);
this.getById("any-div").append(select);

In the previous snippet we can see another Gravity’s feature, the case of requiring to populate a HTML Select, here we just can pass an array of options, it can be a plain Javascript array or some data coming from a JSON response. This way of working is very handy because we don’t have to deal with unnecessary details also giving us the feeling of productivity that we so anxiously seek.

Gravity provides many classes in the View namespace that maps to the most common HTML elements. Also, the name “View” should also give you an idea of another goal we were pursuing: have a Model–view–viewmodel (MVVM) pattern implemented in the frontend with a similar flow and philosophy than we had in backend.

Data Persistence

The model layer in a backend framework is usually accompanied by a persistence paradigm or Object Relational Mapper (ORM) tool based on DataMapper, ActiveRecord or Table Data Gateway. In our case we decided to opt for the former. DataMapper will arrange a clear separation of responsibilities between how the data are structured and how are persisted, this based on ideas taken from Doctrine and Hibernate.

Models can be used to describe data structures and specify domain rules. Data from models can be obtained and persisted to the persistence using these abstractions (in this case an Ajax endpoint):

namespace Models
{
export class Customers extends ModelData.AjaxModel
{
private id : number = 0;
private name : string = "";

public setId(id : number) : void
{
this.id = id;
}

public getId() : number
{
return this.id;
}

public setName(name : string)
{
return this.name = name;
}

public getName() : string
{
return this.name;
}
}
}

To query data using from this model, you can use the Gravity’s Entity Manager this way:

this.em.findOne(
Models.Customers,
{"id" : 5}
).then(customer => {
console.log(customer.getName())
})

Following a convention it tries to find the following action in the backend datasource https://mi-url/project/customers/findOne. Backend endpoints can be customized as needed by the developer.

Another convenient feature in the ORM is the ability to define relationships between models, by doing this you can automatically hydrate relationship references from other models saving lines of code:

namespace Models
{
export class Customers extends ModelData.AjaxModel
{
private id : number = 0;
private name : string = "";
private invoices : Object = [Models.Invoices];

/**
* @param Number id
*/
public setId(id : number) : void
{
this.id = id;
}

/**
* @return Number id
*/
public getId() : number
{
return this.id;
}

/**
* @param Invoices[] invoices
*/
public setInvoices(invoices : Object) : void
{
this.invoices = invoices;
}

/**
* @return Invoices[]
*/
public getInvoices() : Object
{
return this.invoices;
}
}
}

Orchestrating execution

Lastly, we also have controllers or binders. They, alongside ViewModels are charge of managing communication between views and models. Gravity provides the ViewController class that acts as controller/binder that in conjunction with a ViewModel allows the developer to clearly separate application logic and domain model:

namespace Controllers
{
export class BaseController extends View.Controller
{
private viewModel : View.ViewModel = new MyViewModel();

public initialize() : void
{
this.em.find(Models.Customers)
.then(() => this.viewModel.render(customers));
}
}

class MyViewModel extends View.ViewModel
{
public render(customers) : void
{
var div = new View.Div(this);

let select = new View.Select(this.context);
select.build(version, ["id", "name"]);
div.append(select);

this.getByTag("body").append(div);
}
}
}

The ViewModel manipulates the DOM elements required to visualize the data obtained as required.

Conclusion

This is the first article of many explaining the features and advantages of Gravity over other available solutions. We’ll continue working, improving and polishing its components as time goes on, and as I mentioned before, we don’t intend to create any more competition to existing frameworks. In our case we want to create a tool that better solves our problems, adapting better to our work philosophy, taking taking into account our backend background thus being more productive. If you like the ideas shaped in Gravity we invite you to try it out and drop us a message if you find it useful or want to collaborate. Gravity is an open-source framework released under MIT license and is available on Github.

--

--