Rails developers like CRUDs. It’s not really surprising cause framework encourages us to implement our features using create, update, destroy (rails g scaffold anyone?). So whenever new project/feature/change is going to be implemented we always think in CRUD verbs. But is it good?
Let’s start with the requirement:
“I want to be able to assign the account manager to the user who is my client.”
So we have some kind of clients list and our requirement is to assign the manager to the user. Account manager is a new type of object that we have in our system. What are the typical questions we can ask ourselves?
Should it be the update action in the ClientsController?
Should I make an AccountManagersController and place the create action there?
Should I make an AssigmentsController and place the
create action there?
Should I make an update action in the UsersController?
Of course all of them are important questions. We all know that in programming the most difficult parts are where to put the code and how to name variables. Notice that all these solutions have something in common: create and update.
Let’s read the requirement again. Is there any hint that we should use such words? Not really. So whatever option we would choose we would tie our action to either create or update. And we would have a mismatch between our and clients dictionary. For example we would say that we are creating a new assignment, but our client would assign someone.
Another thing is, that create/update is just suggesting that we do action on one resource. And we know from our experience that create action may not only create one object, but lots of them.
First of all we need to stop thinking in a CRUD way. There is a term that I can’t write from the top of my head without making a mistake (I don’t even try to say it). It’s Ubiquitous Language. It was used by Eric Evans in the DDD blue book. Basically it means that we need to build a common language between developers and clients.
So what can we do in our app? The assignment process should be a part of some namespace. We need to ask a question what piece of the system is the assignments module. Maybe it’s something like Account management? Maybe it’s Permissions? Who can assign and when? Don’t be afraid to split the the controller into namespaces that are defined by the parts of the system. The controller should be highly connected to the area of the system and it should be obvious when someone reads the code.
The next step would be the action name. And I think it’s simple. Cause our client used this verb already. Assign. You can go even further and call it assign_account_manager and if you see that there are more and more things to assign, you can always refactor the name, but for this iteration it should be sufficient.
And that’s it. We identified what part of the system this action belongs to, and then we just used simple naming that is common with our client understanding.
I noticed that we are often tempted to think in the Rails way when it comes to introducing new features. We are tied with MVC. We are thinking model controller way. Sometimes we add services for more complex operations. But what if you start thinking in domains of your system? So you can go with the namespace first and then put all you components, like models, or controllers. So if we have
authentication stuff like registration, login, oauth, it could look like this:
You can name however you like. The term
context is used in the phoenix framework. I admire the whole whole phoenix / elixir community that they are not afraid of experimenting with pursuing a better application structure. The term
domain is just commonly associated with the Domain Driven design.
I just encourage you to experiment a bit, and stop thinking in the framework way. The trick is, you need to really understand the application to design correct contexts and put right stuff there. It’s easy to put responsibilties in wrong contexts. But no worries. It’s a learning process. You are learning the domain of the business. You need to fully understand how the application works and how the specific branch of the given business works.
Writing software is hard. It’s often because real world prolems we want to transfer to apps are really complex and dynamic. We need to make everything to simplify the process. Using CRUD may introduce another layer of complexity in your communication with a client. Sometimes our dictionary is strongly influenced by the framework defaults and I think that having two separate dictionaries is complicating the communication a lot.
Remember that we are often just a translator between client and the byte code. So instead of:
Client -> Developer -> Code
let’s try to stick with:
Client and Developer -> Code
Don’t create additional obstacles between you and a client. Programming is hard enough.