It’s no secret that a modern developer is trying to improve efficiency and calls on libraries and frames for help.
The word framework (caracas) became so common that confusion began to occur - what can be called a skeleton, and what is not one?
This work aims to clarify the features, the differences of the frame from the library. There are probably cases in which it is generally difficult to determine that there is a framework or a library in front of us, since the framework can carry with it a set of auxiliary libraries.
Everything is simple with the library. Someone wrote the code, put out the open methods / properties (API) and this can be used. In a sense, the library is a service, and your code is a client.
There are no restrictions on how you build your application library does not impose. You just need to follow the rules for using the library - follow its API.
We conclude that the library imposes restrictions on us at the level of implementation , the stage of construction (coding) of our application.
As an example, here’s a fragment of an imaginary JavaScript library working with names and surnames:
var nameUtil = { correctFullName:function(fullname){ var f = fullname.replace(/^ +| +$| {2}/g, "") f = f.substring(0,1).toUpperCase()+f.substring(1,f.length) f = f.substring(0, f.indexOf(" ")+1) + (f.substring(f.indexOf(" ")+1, f.indexOf(" ")+2)).toUpperCase() + f.substring(f.indexOf(" ")+2, f.length) return f } }
The method “nameUtil.correctFullName” corrects the spelling of the full name of the person, that is, “John leaf” corrects in “John Leaf”. We put this library in the project and just start using its services - we call its methods, that is:
nameUtil.correctFullName(“some Name”)
With the framework, there is another story, the framework imposes restrictions on the level of architecture , the design stage of the application. Moreover, its influence extends to the level of implementation.
An article on Wikipedia , referring to the work of Wolfgang Prie, mentions frozen and hot spots. The source of “Meta Patterns — A Means For Capturing the Essentials of Reusable Object-Oriented Design” refers to hot spots, gray and white.
Let's try to interpret this with the following illustration:
Fig. 1 - Frame and other parts of the system
Blue dots show parts of the frame, they are unchanged. Orange dots are those parts that were created as part of a project.
The following differences between the library and the framework are most often mentioned:
Create a frame and see how we managed to implement the properties of the frame. The framework implements an architectural pattern, in our case it is MVC. The “Publisher Publisher” design pattern has been applied to the event processing part.
Using the frame, we will write a part of an imaginary personnel management application. Our application fragment will only display a list of employees in the table with the ability to filter by experience.
For our system, we write the following components in JavaScript:
EventBus is an instance of the controller, the event bus. In it, we register event subscribers and post events. When an event is posted, the bus finds subscribers by the event signature (identifier) and calls the event handling method. An event bus links all parts of our system. The system exists in a single copy, so create it using the literal notation of JavaScript.
/* * -, , . */ EventBus = { subscribers:[], /* * * @param subscriberObject - * @param subscriberMethod */ subscribe:function(subscriberObject, subscriberMethod, event) { var subscriber = {} subscriber.object = subscriberObject subscriber.method = subscriberMethod subscriber.event = event this.subscribers[this.subscribers.length]=subscriber }, /* * * @param eventId - * @param params * @param callback , * @return */ publish:function(eventId, params, callback){ for(var i=0; i<this.subscribers.length; i++){ var event = this.subscribers[i].event //console.log("eventId=",eventId, " callback=", typeof callback) if(event===eventId){ if(typeof callback=='function'){ callback(this.subscribers[i].object[this.subscribers[i].method](params)) } else { this.subscribers[i].object[this.subscribers[i].method](params) } } } } }
Table - a component of visual display of information in the form of a table. It requires a specific data structure. Implemented as a constructor object, you can create instances.
/* * -, * @param nameParam * @param eBus * @param domId DOM- */ function Table(nameParam, eBus, domId){ var name = nameParam var targetDomId = domId var eventBus = eBus /* * * @param params , */ this.show = function(params){ var data={} data.headers=[] data.rows=[] this.remove() // get data from a data source eventBus.publish(name+ ".getDataSet", params, function(d){ data = d}) var targetDom = document.getElementById(targetDomId) var tableElement = document.createElement("TABLE") var tbodyElement = document.createElement("TBODY") var trElement = document.createElement("TR") trElement.style.background="#eaeaea" for(i=0;i<data.headers.length;i++){ var tdElement = document.createElement("TD") tdElement.appendChild(document.createTextNode(data.headers[i])) trElement.appendChild(tdElement) } tbodyElement.appendChild(trElement) for(i=0;i<data.rows.length;i++){ var trElement = document.createElement("TR") for(j=0;j<data.rows[i].length; j++){ var tdElement = document.createElement("TD") tdElement.appendChild(document.createTextNode(data.rows[i][j])) trElement.appendChild(tdElement) } tbodyElement.appendChild(trElement) } tableElement.appendChild(tbodyElement) targetDom.appendChild(tableElement) tableElement.border=1 } /* * DOM */ this.remove = function(){ var targetDom = document.getElementById(targetDomId) try{ while (targetDom.firstChild) { targetDom.removeChild(targetDom.firstChild); } }catch(e){} } }
DataSource - the data source object instance. He is able to give a certain data structure. Inside it contains a test set of the data itself (data variable).
/* * -, */ DataSource = { /* * * @return */ loadDepartments:function(){ return data } } // var data = [ {name:"IT", employees:[ {name:"Federico", surname:"Gonsales", position:"Engineer", hirenDate:"2013-01-02"}, {name:"Mike", surname:"Saldan", position:"Tester", hirenDate:"2011-11-22"}, {name:"Leo", surname:"Sigh", position:"Architect", hirenDate:"2001-12-12"} ] }, {name:"Sales", employees:[ {name:"Sarah", surname:"Connor", position:"Manager", hirenDate:"2010-04-14"}, {name:"Richard", surname:"Senom", position:"Specialist", hirenDate:"2014-05-07"} ] } ]
Employee is a model constructor object representing an object of the domain - the Employee.
function Employee(nameParam, surnameParam, positionParam, hirenDateParam){ var name = nameParam var surname = surnameParam var position = positionParam var hirenDate = hirenDateParam this.setName = function(n){ name=n } this.setSurname = function(s){ surname=s } this.setPosition = function(p){ position=p } this.setHirenDate = function(d){ hirenDate=d } this.getName = function(){ return name } this.getSurname = function(){ return surname } this.getPosition = function(){ return position } this.getHirenDate = function(){ return hirenDate } this.getFullName = function(){ return name+" "+surname } this.getExperience = function(){ var oneDay = 24*60*60*1000; var now = new Date(); //console.log(hirenDate.getTime() +"-"+ now.getTime()) var diffDays = Math.round(Math.abs((hirenDate.getTime() - now.getTime())/(oneDay))) return (diffDays/365).toFixed(0) } }
Department is a model constructor object representing a domain object — Department.
/* * - , * @param nameParam */ function Department(nameParam){ var name = nameParam var employees = [] this.setName = function(n){ name=n } this.addEmployee = function(e){ employees[employees.length] = e } this.getName = function(){ return name } this.getEmployees = function(){ return employees } }
Main - the main object of the application, connects all together. In terms of use, the framework makes its own rules. To place our table on the page (Table), follow these steps:
Create an instance of Table specifying the event handler generated by the visual component.
In response to a call with the “getDataSet” parameter, the event handler must return a JSON structure of the form:
[headers: [“first”, “second”], rows: [[value1, value2], [value3, value4]]]
Looking at the “Main” object it may seem that we do not need to create instances of the model in order to send the data set to the “Table” component, but this is not so. Model objects contain business logic that should not be in the controller, for example, calculating employee experience (“getExpirience” method)
/* * -, , , * , Table */ var Main = { /* * , * , */ init:function(){ var myTable = new Table("myTable", EventBus, "employeeTable") EventBus.subscribe(myTable, "show", 'employee.showTable') EventBus.subscribe(this, "getEmployeesDataSet", "myTable.getDataSet") EventBus.subscribe(DataSource, "loadDepartments", "loadDepartments") }, /* * , , * @param params */ getEmployeesDataSet:function(params){ var data EventBus.publish("loadDepartments", null, function(d){ data = d }) var departments = [] for(i=0; i<data.length; i++){ department = new Department(data[i].name) for(j=0;j<data[i].employees.length; j++){ var h = data[i].employees[j].hirenDate var hirenDate = new Date(h.substring(0,4), h.substring(5,7), h.substring(8,10)) employee = new Employee(data[i].employees[j].name, data[i].employees[j].surname, data[i].employees[j].position, hirenDate) department.addEmployee(employee) } departments[i] = department } records = [] var c=0 for(i=0;i<departments.length;i++){ department = departments[i] employees = department.getEmployees() for(j=0;j<employees.length;j++){ if(params){ if(params.expirience){ if(employees[j].getExperience()*1 >= params.expirience*1){ records[c] = [employees[j].getFullName(), employees[j].getPosition(), employees[j].getExperience(), department.getName()] c++ } } }else{ records[c] = [employees[j].getFullName(), employees[j].getPosition(), employees[j].getExperience(), department.getName()] c++ } } } var dataSet={ headers:["Full name", "Position", "Expirience", "Department"], rows:records } return dataSet } }
In Figure 2 we will try to show the belonging of classes to parts of the MVC pattern.
Fig. 2 - Parts of the application
In Figure 3, we show the messaging sequence.
Fig. 3 - Sequence Diagram
Conditionally call what is created “code set”.
“Dialing” does not oblige the creation of domain model constructors. In Main.js, the data source for Table.js can be anything. The framework, its implementation of the architecture (MVC) is not relevant. We simply call the Table.js method with a specific parameter. This is a property of the library.
“Dialing code”, when using the visual component Table.js, is obliged to give it data of a certain structure. This is not a MVC requirement, therefore it has nothing to do with the framework. This is a library property.
“Dialing” obliges visual components to send their events through the event bus and so that there is a “listener” - the subscriber of this event. The presentation is separated from event handling, management, this is already an element of MVC. This is a frame property. The skeleton code (EventBus.js) will call our code. This is a frame property.
From the MVC architecture, directly through the code, it was possible to realize the requirement to create visual components separately from the control components. It was not possible to create a domain model. Consequently, the creation of a model is done by agreement, since we follow the MVC pattern.
If you notice what is written by you or used component:
a) brings to the project any architectural pattern
b) control of key execution threads is transferred to the component
c) the component requires from you some organization of your parts of the application, then you are dealing with a framework.
Getting rid of the frame in the project is much more difficult than from the library. The library can be replaced by correcting the API calls of the old library to the calls of the new one or by writing the library implementation itself. A framework forces one to build an application in a certain way, to organize, bind structural units of code according to certain rules. In addition, frames are usually much more complicated than libraries.
This does not detract from the importance of the frameworks, they bring to the project a proven, well-known architecture, set the rules for organizing the application, serve as a framework to keep developers from inventing their specific solutions. All this makes the software more supported.
Ideally, it is good that the implementation of the framework can be easily changed. While the Java world is approaching this, in which, thanks to the specifications, the standard is set, its API, and various manufacturers can implement it.
Source: https://habr.com/ru/post/315900/
All Articles