The MVC Architecture and how Sinatra sings to our backend

What is the MVC Architecture?

Alie Brubaker
5 min readAug 22, 2022

MVC stands for Model-View-Controller and the main takeaway is that using it helps us separate concerns. By keeping each aspect of the program contained within its own area of responsibility, we optimize our ability to test our code in extremely specific circumstances.

Model

The model portion of the framework represents the logic that directly manipulates the database. All of the CRUD (create, read, update and destroy: the words associated with the various HTTP verbs that allow requests over the internet to perform those four actions) requests made by the view and which are initiated by the controller end up at the model so it can add, change or remove data from the database.

View

The view is essentially the UI created by the front-end of the application. It has two main roles: rendering and re-rendering the app, and taking input from the user and requesting that the controller ask the models to change the database in sync with those requests.

Controller

The controller is the bridge that ties the user, through the view, to the database, through the models. It asks the models to make the changes that the view is requesting through those CRUD actions and at those specific points.

Diagram depicting MVC Architecture
A simple diagram of how the three pieces of the framework work together. Source (https://www.technoarchsoftwares.com/blog/mvc-framework/)

MVC has a few extremely advantageous aspects, though any architectural approach will have trade offs. One of the most important advantages of this style is the separation of concerns. With the controller joining together the model and view, there is a reasonable expectation that work occurring on both the front end and the back end will not conflict. Similarly, the modular approach makes this style of architecture very easy to test as the logic that makes up the models and controller can be tested independently. Applications using MVC are doubly granular as they are made up of distinct classes or objects, which makes for even easier testing.

The reduction in complexity is another advantage of MVC. Each piece has only it’s specific responsibilities and thus it is extremely easy to follow. In addition to being easy for engineers to follow, applications built using MVC are generally SEO friendly, allowing for greater search optimization.

The main and maybe even major disadvantage to using an MVC architecture is that it generally requires knowledge of multiple technologies, libraries or frameworks in order to use it properly. Specifically, a library or framework, or even multiple frameworks, designed for the models and controllers on the back-end.

At Flatiron, we are currently learning to work with Sinatra for the controller and ActiveRecord for the models. Sinatra dove-tails nicely with React and specifically the React Router hook, which makes the server endpoints and the routes on the front end extremely easy to work in tandem.

ActiveRecord alone takes vanilla Ruby and hands classes five times as many methods out of the box, saving the programmer from needing to establish their own getters and setters and making associations between tables in the database extremely rudimentary to initialize. After creating and migrating two tables, users and comments, each might have a very simple model like so:


class User < ActiveRecord::Base
has_many :comments
endclass Comment < ActiveRecord::Base
belongs_to :user
end

The use_many and belongs_to macros alone save a great deal of time and give the User and Comment classes another set of useful association methods.

We might hook those database tables to something that a user could interact with in their UI by setting up a controller. An application_controller.rb file in another directory of the file structure like below allows us to set routes for our front-end to make requests to.

class ApplicationController < Sinatra::Base  #sets the default Content-Type that the server accepts as json
set :default_content_type, 'application/json'
get '/users' do
users = User.all
users.to_json
endend

If a user were to path to http://insert-domain-here/users in their address bar, they would see a representation of each row of data in the users table of the database formatted as json objects with the table column names as keys. Obviously, that isn’t going to do a typical end-user much good, but a software engineer will definitely make quick work of displaying that information in a user digestible way. That is where our front end comes in with React. We will display those json objects with the useEffect hook and a fetch request that loads after the initial render, but for the purposes of this simple demonstration we’ll hook up our App component to React Router to show how resources can be linked to components.

// App.jsimport {Routes, Route} from 'react-router-dom'
import User from '/components/User.js'
import NavBar from '/components/NavBar.js'
export default function App() {
return (
<>
<NavBar />
<Routes>
<Route path={'/users'} element={<User/>} />
</Routes>
</>
)
}
// components/NavBar.js
import {NavLink} from 'react-router-dom'
export default function NavBar() { return ( <NavLink to='/user' >
User
</NavLink>
)
}
// components/User.js
import {useEffect, useState} from 'react'
export default function User() { const [users, setUsers]= useState([]) useEffect(() => {
fetch('http://insert-domain-here/users)
.then(r => r.json())
.then(userData => setUsers(userData)
},[])
return (
<div className='users'>
{users.map(user => <p>{user.username}</p>)}
</div>
)

}

So our user clicks the User link in the navigation maybe located in a header or sidebar and the User component renders with the /user endpoint in the address bar and our fetch pulls our users json from our backend, parses the response and displays a list of usernames.

There are a large number of things going on under the hood that have their own explanations, but these three code blocks illustrate the basic functionality of React and React Router, Sinatra and ActiveRecord. Each code block represents one of the three aspects of MVC. From this starting point we might have a slew of SQL queries in our models or our controller to limit the volume of what is retrieved from our fetch request, or perform back-end validation on use input, or dozens of other manipulations that save on processing time and space while still retrieving the resources we need from out database.

Though the example above is extremely basic, it is easy to see how each piece has its part to play in the bigger picture of the application. The MVC architecture is easy to follow and take piecemeal for testing.

--

--

Alie Brubaker

I’m a 36 year old Canadian transgender recent Flatiron School Software Engineering bootcamp graduate looking for work