I'm creating a new application and would like to use Mithril 1.x, however, I have some doubts about the architecture.
Which of the following architectures would be most appropriate?
1-
/model
user.js
var model = {
getUsers: function() {
return m.request...
}
}
/views
user.js
var state = {
users: []
}
var user = {
oninit: function(vnode) {
model.getUsers().then(function(users){
state.users = users
})
},
view: function(vnode) {
return m("div", [
state.users.map(function(user){
return m("p", user.name)
})
])
}
}
2-
/model
user.js
var model = {
users: [],
getUsers: function() {
return m.request().then(function(users) {
model.users = users
})
}
}
/views
user.js
var user = {
oninit: function(vnode) {
model.getUsers()
},
view: function(vnode) {
return m("div", [
model.users.map(function(user){
return m("p", user.name)
})
])
}
}
I'm a fan of 2. I have several apps in production which all use a global state object coupled with stateless components.
Considering you can reuse the already fetched users in others components I would stay with 2.
I do 2 myself
I'd vote against both of them. In both 1 and 2 modelis a singleton. While component being a singleton is OK in a lot of situations, making model a singleton will make tests much more complex. You will have to mock server requests. Some tests will require one response, others will require another. You will have to modify parts of model in every tests you will write. This will inevitable cause problems.
Why not to pass the model instance via vnode.state?
While component being a singleton is OK in a lot of situations, making model a singleton will make tests much more complex
It really depends on what type of tests you want to write. A singleton model/state makes it very easy to write Acceptance Tests [1], which are really the critical tests for an end-user app. Unit Tests [1] are better for a deliverable library or app internals that has explicit API contracts that cannot regress. A singleton model makes Unit testing more challenging since there's less purity/isolation and more side-effects. All arguments I encounter seem to miss this distinction. As always, the answer depends on what you're building and for whom.
[1] http://softwaretestingfundamentals.com/acceptance-testing/
@chebum thank you for the reply!
I could not understand very well, could you give me an example?
@leeoniya good point. Did you mean that overriding model is basically simpler when it's a singleton? Why not to make it a factory ("virtual" function) that creates a model and injects it into components. It will be almost as easy to override for end-to-end tests while still allow writing unit tests. What do you think?
@marciomunhoz for tests you will need to override the model like that:
model.getUsers = function() {
return [1,2,3]; //Fake collection to prevent server request
}
There are several problems with this approach when writing unit tests:
getUsers method may have important side effects that we will need to replicate in test overloads.getUsers method.@marciomunhoz did this help? Please close it out if this isn't generating useful discussion.
@tivac ok! thanks!
Most helpful comment
I'm a fan of 2. I have several apps in production which all use a global state object coupled with stateless components.