TL; DR;
I'm looking for trite example of DDD node.js application.
Hi,
I'm going to create node application. I wonder that I can not find any example of application with business logic separated in domain.
OK, there are some examples like:
https://github.com/adrai/node-cqrs-domain - but this is whole CQRS with event sourcing implementation.
My idea is to do that like that:
//domain/book.js
function Book(title, author)
{
this._title = title;
this._author = author;
}
// domain methods ...
//infrastructure/persistance/repository/book-repository.js
function BookRepository()
{}
BookRepository.prototype.save(book)
{
var bookModel = mappers.mapToOrm(book);
return bookModel.save();
}
// [...] get, getAll, getNextId
//infrastructure/persistance/orm/book.js
//using http://bookshelfjs.org/
var Book = bookshelf.Model.extend({
tableName: 'books'
});
//infrastructure/mappers/book-mapper.js
function mapToOrm(book) {
//mapping [...]
return new persistance.Book();
}
function mapToDomain(domain) {
//mapping [...]
return new domain.Book();
}
but on the other hand I've never seen any similar solution (with domain model, orm model, repository and mappers). Am I thinking in the right way? Maybe there is no reason to separate business logic in domain in node.js applications. If so, why? If not, can you send me an example of DDD implementation or improve my code?
[2017/01/13]
I've created sample application in TypeScript. For now without repositories and not much services. Issues and pull requests are welcome.
https://github.com/dawiddominiak/ddd-typescript-bin-packing-problem-solution
I'm very new to Node.js world.
But I believe if you do your work using TypeScript with Node you can force most of DDD principles to be used.
The problem "and advantage in the same time" in node.js that there aren't so restrictions like we have in OOP languages like C# or Java. and this freedom "and messy" of JavaScript making create robust complex DomainModel and Business logic very hard
I'm looking to do the same thing at the moment, and I'm coming from the Ruby world. So, let me do 2 things:
Point you to the best Ruby implementation I've seen of Domain-Driven Design I have found, Hanami: http://hanamirb.org/guides/models/overview/ which you could use as a reference.
Discuss what I'm finding (literally right now, as I type) to attempt to find the analogs in Node.
I've found this page: https://github.com/sindresorhus/awesome-nodejs
which catalogs a ton of high-quality / high-popularity Node packages.
The first thing is, we need something that is going to do validation and schema construction for our Domain Models. Just looking at the first entry in the data validation section, Joi seems to be a decent choice for that:
https://github.com/hapijs/joi
For Persistence of the domain objects, I'm just setting up a stub object, borrowing from Hanami's interface:
var repo = {
find: function(entity_name, id) {
// - Fetch an entity from the collection by its ID
},
create: function(entity_name, data) {
// – Create a record for the given data and return an entity
},
update: function(entity_name, id, data) {
// – Update the record corresponding to the id and return the updated entity
},
delete: function(entity_name, id) {
// – Delete the record corresponding to the given entity
},
all: function(entity_name) {
// - Fetch all the entities from the collection
},
query: function(entity_name, query_object) {
},
first: function(entity_name) {
// - Fetch the first entity from the collection
},
last: function(entity_name) {
// - Fetch the last entity from the collection
},
clear: function(entity_name) {
// - Delete all the records from the collection
}
}
module.exports = repo
whether you choose to use Bookshelf
, Sequelize
, or even the LoopBack
framework, you can code an object that is going to fit the above interface that then does the dirty work of integrating with those frameworks.
If I were to try different ORM's, I would create a different repo object for each of the above. Notice that as I've written it, the repo is a singleton that is aware of different entities and how to persist them. In many cases, this will no doubt delegate to different repository objects on a per-entity basis. However, that might not always be true. a simple in-memory repo, could just have an array of objects for each entity.
That leaves Services/Interactors - The functions/classes that actually do work. These are easy - they are the ones that take a domain object, perform some business logic, and in the CRUD cases, make a call out to the Repository. A probably-syntactically-wrong example:
const repository = require('./myFileRepository')
function createBook(bookEntity) {
if(bookEntity.valid?) {
repository.create('book', bookEntity)
return true
}
else {
return { error: 'book not valid' }
}
}
module.exports = createBook
for the Service functions, I just today learned about Node Machines, and they seem like a really smart idea: http://node-machine.org
they seem to be a JS-attempt at monads + documentation. so I'm considering writing them up like that.
anyway, given it's been a year since your post, you've probably moved on. hope this helps you / the community!
Many would argue that JavaScript is NOT well suited to modeling a complex problem into a domain model and then into code. That's especially the case if the domain is in business, industry and commerce, rather than in computer or data science.
I'm not saying one can't create a domain model in JavaScript. Just like one could create one in C. But does that mean one should?
The example you give uses some terminology in domain-driven design, but misses the whole purpose and ethos of applying it.