Think outside the Model Box
This article is a continuation of “Controllers, the right way!”. It will help you understand a way to achieve a good application structure.
This is a continuation of “Controllers, the right way!” and I’ve got a lot of feedback on it! Thanks guys.
If you read the article you already know the purpose (good application structure and deep understanding of MVC) of this articles. If you didn’t read it, care to take a look!
Ok then, let’s dive a bit more on this subject and try to understand how can we correctly structure our application.
Reading this question is the perfect way to understand the difficulties a developer will probably face when trying to better structure his application following the advice of “Controllers, the right way!” and a good starting point to understand the purpose of this article.
First of all, let’s understand what a Model in a MVC context is. I would love that this part of the article was interactive with the reader, so that everyone could see all the answers. But let’s summarize this, I bet all the answers would have database in it.
Common sense is that the Model it’s where you put your database stuff, problem is, your application requires a lot more logic than a simple database access class, it needs to send notifications, call other services, do some validation, etc.
So the question remains…
“If it’s not in the Controller, not in the Model, and certainly not in the View where the hell am I going to put the application logic ?”
I believe this problem is deeply connected to how the majority of the MVC frameworks out there structure our applications from the start. Pretty much all of them have something like a Controllers folder, a Models folder and a Views folder, this leads to a common mental roadblock that holds you from good design.
I’m not telling these frameworks don’t well structure your application, it’s totally fine to keep it for small/mid applications, but while you keep growing your application you’ll start to feel the need to restructure the application, and you’ll start to ask yourself, ‘where should I put these?’.
“As you may have noticed, a key to solid application design is simply separating responsibilities, or creating layers of responsibility. Controllers are responsible for receiving an HTTP request and calling the proper business layer classes. Your business / domain layer is your application. It contains the classes that retrieve data, validate data, process payments, send e-mails, and any other function of your application. In fact, your domain layer doesn’t need to know about “the web” at all! The web is simply a transport mechanism to access your application, and knowledge of the web and HTTP need not go beyond the routing and controller layers. Good architecture can be challenging, but will yield large profits of sustainable, clear code.
For example, instead of accessing the web request instance in a class, you could simply pass the web input from the controller. This simple change alone decouples your class from “the web”, and the class can easily be tested without worrying about mocking a web request”
Excerpt From: Taylor Otwell. “Laravel: From Apprentice To Artisan.”
Ok, so let’s just clear our minds about the Model concept, in fact let’s delete the Model folder and think outside the Model box.
And how can we do this? Let’s make a small change in the code we’ve used at “Controllers, the right way!” to understand this.
# UserController
function update(request)
# 1. get the input
# 2. tries to update the info using some core application
domain object and return success response
# 3. if it fails return response with errors
input = request.post
try
UserService.update(input)
return Response(RenderView.success)
catch ValidationException e
return Response(e.errors())endfunction
So imagine you want some User application logic, you could create a folder called Services, with a UserService class and a UserRepository class that will handle your database access.
And here’s the modified UserService.
# UserService, where your business/domain layer isClass UserService()
function create()
# some code
endfunction function delete()
# some code
endfunction function update(input)
rules[‘email’] = ‘required|email’
if input[‘password’]
rules[‘password’] = ‘min:6'
endif
validator = new Validator(rules, input)
if validator.fails()
Throw ValidationException(validator.errors)
else
## NOTE: UserRepository instead of a model
UserRepository.update(input)
return
endif
endfunctionendclass
This may seem to you a very little and irrelevant modification, but it will help you to think outside the box when trying to structure your application!
Follow up my blog posts to future examples on writing well structured and maintainable applications.