Friday 2 October 2015

Dependency Injection в Node.js

Dependency injection is a software design pattern in which one or more dependencies (or services) are injected, or passed by reference, into a dependent object.

Причины для использования Dependency Injection


Развязка


Внедрение зависимостей делает ваши модули менее связаны приводит к более обслуживаемой кода.


Легче модульного тестирования


Вместо того чтобы использовать жестко закодированные зависимостей вы можете передать их в модуль вы хотели бы использовать. С этой картины в большинстве случаев, вы не должны использовать модули, как proxyquire.


Ускорение разработки


С инъекции зависимостей, после интерфейсы определены легко работать без каких-либо конфликтов слияния.


Как использовать Dependency Injection используя Node.js


Во-первых, давайте взглянем на то, как вы могли бы написать свои приложения без использования инъекции зависимостей, и как бы вы преобразовать его.


Образец модуля без dependency injection


// team.js
var User = require('./user');

function getTeam(teamId) {  
  return User.find({teamId: teamId});
}

module.exports.getTeam = getTeam;  

Простой тест будет выглядеть так:


// team.spec.js
var Team = require('./team');  
var User = require('./user');

describe('Team', function() {  
  it('#getTeam', function* () {
    var users = [{id: 1, id: 2}];

    this.sandbox.stub(User, 'find', function() {
      return Promise.resolve(users);
    });

    var team = yield team.getTeam();

    expect(team).to.eql(users);
  });
});

То, что мы сделали здесь является то, что мы создали файл с именем team.js, которые могут возвращать список пользователей, которые принадлежат к одной команде. Для этого нам потребуется модель User, так что мы можем вызвать его метод, который возвращает find список пользователей.


Выглядит хорошо, не так ли? Но когда дело доходит до тестирования, мы должны использовать тестовые заглушки с sinon.


В тестовом файле, мы должны потребовать модель User, так что мы можем заглушки свой метод find. Заметьте, что мы используем функцию песочницы здесь, так что мы не придется вручную восстановить исходную функцию после выполнения теста.


Sample module with dependency injection


/ team.js
function Team(options) {  
  this.options = options;
}

Team.prototype.getTeam = function(teamId) {  
  return this.options.User.find({teamId: teamId})
}

function create(options) {  
  return new Team(options);
}

Вы можете проверить это файл со следующим теста:


// team.spec.js
var Team = require('./team');

describe('Team', function() {  
  it('#getTeam', function* () {
    var users = [{id: 1, id: 2}];

    var fakeUser = {
      find: function() {
        return Promise.resolve(users);
      }
    };

    var team = Team.create({
      User: fakeUser
    });

    var team = yield team.getTeam();

    expect(team).to.eql(users);
  });
});

Хорошо, так как версия с инъекции зависимостей отличается от предыдущей? Первое, что можно заметить, является использование factory pattern: мы используем это, чтобы придать вариантов / зависимостей для вновь созданного объекта - это когда мы можем придать модели User.


В тестового файла мы должны создать поддельный модель, которая будет представлять модель User, то мы просто ввести это путем передачи его в create функции Team модели. Легко, не так ли?


Dependency Injection в реальных проектах


Вы можете найти примеры внедрения зависимостей в много проектов с открытым кодом. Например, большинство Express/Koa middlewares, которые вы используете в вашей повседневной работе использует ту же самую подход.


Express middlewares


var express = require('express');  
var app = express();  
var session = require('express-session');

app.use(session({  
  store: require('connect-session-knex')()
}));

Фрагмент кода выше, используя зависимость инъекций с заводской схеме: на сессии промежуточного мы передаем модуль connect-session-knex - он должен реализовать интерфейс, что модуль session будет звонить.


В этом случае модуль connect-session-knex должен реализовать следующие методы:


  • store.destroy(sid, callback)
  • store.get(sid, callback)
  • store.set(sid, session, callback)

 

No comments :

Post a Comment