I. Remove Unused Code
Removing unused code is an integral part of maintaining source code in a software project. It helps clean up the codebase and reduces complexity, making the code easier to understand and maintain in the future.
II. Limit Data in Controller Methods
Thin controllers are easy to test and have good performance because there’s overhead involved in passing the controller instance variable around.
III. DRY (Don’t Repeat Yourself)
DON’T
def published?
state == 'published'
end
def draft?
state == 'draft'
end
def spam?
state == 'spam'
end
SHOULD BE
STATES = ['draft', 'published', 'spam']
STATES.each do |state_name|
define_method "#{state_name}?" do
state == state_name
end
end
In the above case, we can use enums instead of this.
IV. Eager Loading
Eager loading is a way to solve the classic N + 1 query performance problem caused by inefficient use of child objects.
Let’s look at the following code. It will fetch the zip of 10 users.
DON’T
users = User.all(limit: 10)
users.each do |user|
puts user.address.zip
end
SHOULD BE
users = User.includes(:address).limit(10)
users.each do |user|
puts user.address.zip
end
V. Use Indexes
Database indexing is one of the simplest ways to improve database performance. The INSERT or UPDATE operation will become slower but will boost fetching data which is more frequently used in web applications.
VI. Avoid Dynamism
Although find_by
and find_by_xyz
dynamic methods are convenient, they are also slow because each one needs to run through method_missing
and parse the filename against the list of columns in the database table.
VII. Caching
There are many typical types of caching, such as HTTP Caching, Page Caching, Counter Caching, Proxy Caching, Fragment Caching,…
HTTP Caching: This is a mechanism that web browsers and web servers use to store (cache) HTTP resources such as HTML, CSS, JavaScript, images, and other media resources. This helps reduce page load times by fetching resources from the cache instead of re-requesting them from the server.
Page Caching: This involves storing entire web pages that have been generated and displayed to users, helping to reduce response times and page load times. Content Management Systems (CMS) often use page caching to speed up access to dynamic web pages.
Counter Caching: Used to store counts or other counting-related information instead of recalculating it each time there is a request. This reduces the load on the database and improves the performance of counting-related functions, such as counting the number of views for a blog post.
Proxy Caching: Proxy caching occurs when a proxy server caches requested resources from the origin server and serves them directly to subsequent requests from clients, rather than waiting for the origin server’s response. This reduces the load on the origin server and improves performance for end users.
Fragment caching: Is a technique in Ruby on Rails (and many other web frameworks) that allows you to cache a portion of a view or a fragment of a webpage instead of caching the entire page or all data. This enables you to optimize the performance of your web application by caching only the parts of the page that truly need caching, while still allowing other parts of the page to be rendered as needed.
Each type of caching has its own applications and benefits in different situations. In future articles, we can explore each type of caching in detail and how they can be deployed and optimized in web systems and applications.
VIII. Image Spriting
In websites, a significant amount of time is consumed for loading a large number of images. One way to minimize this is to sprite your images. This will reduce the number of images to be served significantly.
IX. Use a CDN
A CDN (content delivery network) is an interconnected system of computers on the Internet that provides web content rapidly to numerous users by duplicating the content on multiple servers and directing the content to users based on proximity.
When concurrent users come to your site, using a CDN rather than serving assets (like images, JavaScript, stylesheets) from your server will boost performance.
X. Minify and Gzip Stylesheets and JavaScript
This is the last point, but an important one. You can reduce the size of stylesheets and JavaScript significantly by minifying them and serving them in GZip format. It will improve performance significantly by reducing request/response time.
XI. Specify which columns you need if possible
If you need to get the only email of user
User.limit(100).map(&:email)
Can Be…
User.select(:email).limit(100).map(&:email)
Better
User.limit(100).pluck(:email)
Helpfully, if you just need a few values, you can use ActiveRecord#pluck to avoid instantiating ActiveRecord objects.
XII. Use Background Jobs
We should use background jobs for:
- Tasks that need to spend a longer time to complete than a normal request.
- Tasks that need not return an immediate response to the user.
XIII. SQL Injection
Example:
params[:id] = "1 = 1"
User.find_by(params[:id])
Query
SELECT "users".* FROM "users" WHERE (admin = 't') LIMIT 1
Result
#<User id: 30, name: "Admin", password: "supersecretpass", age: 25, admin: true, created_at: "2016-01-19 16:12:11", updated_at: "2016-01-19 16:12:11">
XIV. Disable serve_static_files
(or serve_static_assets
) on production
We shouldn’t rely on serving assets from public/
via your Rails app. It’s better to let the web server (e.g., Apache or Nginx) handle serving assets for performance.
Public comments are closed, but I love hearing from readers. Feel free to contact me with your thoughts.