53 câu hỏi thường gặp khi phỏng vấn Ruby (phần 1)

Hy vọng bài viết sẽ có ích cho những bạn chuẩn bị đi phỏng vấn, còn nếu ko đi phỏng vấn, thì có thể đọc và thử trả lời xem mình có thể trả lời được bao nhiêu câu nhé 😎

1. Hãy mô tả quy trình request/response khi truy cập một danh sách bài viết (articles) trong blog?

Khi người dùng click vào button, một request GET từ URL /articles được gửi tới web server. Rails sẽ thực thi action #index trên URL /controller tương ứng trong route.rb.

Controller gọi Article.all để load tất cả bài viết từ database thông qua model Article. Kết quả được gán vào 1 biến instance. View hiển thị danh sách bài viết dựa trên giá trị của biến instance.

2. (Hầu như) mọi thứ trong Ruby đều là đối tượng (object). Hãy giải thích điều này?

Trong lập trình hướng đối tượng, object là một thể hiện của class, một phần của class đó cung cấp cho các phương thức để bạn có thể sử dụng. Ví dụ số 12 không chỉ là một con số, nó là một object và Ruby cho phép bạn thực hiện những thứ như cộng, nhân,... ví dụ như 12.class hay 12+3.

Trong Ruby, mọi class đều là instance của class Class.

7.class => Fixnum
7.class.class => Class

Một vài thứ không phải object như blocks, methods, conditional statements (ví dụ như if, else).

Câu hỏi này được hỏi để xem bạn có hiểu hầu như mọi thứ trong Ruby đều hoạt động tương tự nhau, đó là điều giúp cho Ruby trở nên dễ học hơn các ngôn ngữ khác. Bạn có thể đọc thêm về cái này ở đây.

3. Ruby là statically hay dynamically typed?

Ruby là dynamically typed. Đó là lý do bạn có thể thay đổi kiểu biến ở mỗi dòng mà không gây ra lỗi gì cả.

x = 1
x = "foo"

để hiểu hơn về statically hay dynamically typed, bạn có thể đọc thêm ở đây.

4. Hãy nói về getters và setters trong Ruby

Getter cho phép truy cập một biến instance. Setter cho phép setting 1 biến instance. Ruby cung cấp 3 phương thức để định nghĩa getter và setter: attr_reader (getter), attr_writer (setter), và attr_accessor (setter và getter).

5. Điều gì sẽ xảy ra khi gọi một phương thức trong Ruby?

Một thông điệp chưa tên phương thức được gửi tới đối tượng. Nếu phương thức tồn tại trong đối tượng, đối tượng sẽ gọi nó. Điều này được thể hiện rõ ràng hơn ở phương thức send() của Ruby.

6. Làm thế nào để lấy ra tất cả routes trong app?

rake routes

Có thể thêm | grep <keyword> để filter các router mình cần.

7. Gemfile là gì?

Gemfile là một tiện ích của gem Bundler được sử dụng để quản lý các gem được sử dụng trong application của bạn, nó được đặt trong thư mục gốc của dự án.

8. Gemfile.lock là gì?

File này liệt kê các version chính xác của từng gem đã được installed, nó cũng là version có thể được installed nếu clone dự án sang một máy khác. Nếu không chỉ định cụ thể version của gem trong Gemfile thì nó sẽ xtuwj động install version mới nhất của gem.

9. Bạn đã từng dùng những design patterns nào trong Rails? Các design patterns trong Rails bao gồm service objects, value objects, form objects, query objects, view objects, policy objects, và decorators.

Để đi sâu vào từng cái thì bạn có thể đọc ở đây để hiểu thêm.

10. Rails quản lý database như thế nào?

Thường thì chúng ta sẽ tự generates và thêm các hướng dẫn vào trong file migration. Nó sẽ hướng dẫn ActiveRecord cách để sửa đổi database hiện tại. Do đó, việc sửa hay thay đổi các migration trước đó là điều không được khuyến khích, nó có thể khiến database bị sai so với mong muốn.

11. count, lenghtsize khác nhau thế nào?

  • count: sinh ra 1 câu query để đếm tổng số record, thường được dùng khi có sự thay đổi trong DB và bộ nhớ.
  • length: trả về số bản ghi trong bộ nhớ. Nó nhẹ hơn so với count vì không phải truy vấn vào database, tuy nhiên nếu chưa được lưu trong bộ nhớ, nó sẽ thực hiện 1 câu lệnh để lưu toàn bộ vào bộ nhớ. Nó còn có thể được dùng để đếm số kí tự trong 1 chuỗi.
  • size: là sự kết hợp của countlenght, nếu đối tượng chưa được lưu vào bộ nhớ, nó sẽ giống như count, ngược lại giống như length.

12. Bạn đã từng xử lý phân quyền như thế nào?

Phân quyền là việc cho phép những người dùng khác nhau có các cấp truy cập khác nhau. Có một số gem như PunditCanCanCan hỗ trợ phân quyền rất tốt.

13. Callbacks là gì?

Callbacks là một phương thức của Active Record, nó sẽ được gọi tới vào một thời điểm nào đó trong vòng đời của một đối tượng. Callback thường được dùng để thực thi các phương thức logic trước hoặc sau khi đối tượng có một sự thay đổi nào đó, ví dụ như before_validation, after_save, after_destroy,...

14. Khi nào nên sử dụng before_save và after_save?

Update một bản ghi sau khi nó được lưu sẽ tạo thêm 1 câu truy vấn vào database, cho nên, nếu muốn thay đổi 1 thuộc tính của object thì dùng before_save sẽ tiện hơn.

Đôi khi một số thông tin bắt buộc phải có để tạo bản ghi nhưng lại chưa tồn tại, ví dụ như id của bản ghi có liên kết với nó, trong trường hợp này ta sử dụng callback after_save

15. initializers trong Rails là gì?

Initializers chứa configuration logic và chỉ được chạy khi khởi động app. Có nghĩa là mỗi lần thay đổi initializers thì phải khởi động lại Rails server. Nó nằm trong thư mục /config/initializers

16. Delete và destroy khác nhau như thế nào?

  • delete: xóa bản ghi
  • destroy: xóa bản ghi và thực hiện callback

Callback liên quan đến destroy hay được dùng nhất là dependent: destroy trong file model. Ví dụ, khi xóa 1 bài viết thì sẽ xóa các comment liên quan

class Article < < BaseController
  has_many :comments, dependent: :destroy
end

17. "Fat models, skinny controllers" là gì?

Xử lý logic nên được đặt trong model thay vì controller, nó giúp dễ thực hiện unit test và sử dụng lại hơn. Controller chỉ giúp truyền thông tin giữa view và model.

18. "Skinny controllers, skinny models" là gì?

Khi phát triển codebase, model dễ trở nên quá to, nó chứa quá nhiều thứ và khó quản lý. Chúng ta có thể giữ model gọn gàng hơn bằng cách chuyển các phần code logic cồng kềnh sang design patters khác như service object.

19. Class method và instance method khác nhau như nào?

Class method là method mà được gọi trên một lớp, còn instance method là method mà được gọi trên thể hiện của một lớp. Ví dụ:

class Greeting
  def self.hello_from_class
    puts 'class: hello'
  end
  def hello_from_instance
    puts 'instance: hello '
  end
end
# class method
Greeting.hello_from_class # => 'class: hello'
Greeting.hello_from_instance # => NoMethodError: undefined method ‘hello_from_instance’ for Greeting:Class
# instance method
g = Greeting.new
g.hello_from_instance # => instance: hello

hello_from_class là một class method nên khi ta gọi Greeting.hello_from_class thì nó hoạt động tốt nhưng hello_from_instance lại là một instance method dó đó khi ta gọi Greeting.hello_from_instance thì lập tức ruby sẽ bắn ra một exception là NoMethodError.

Trong thực tế, chúng thường được dùng cho mục đích khác nhau. Cụ thể hơn bạn có thể đọc trong bài viết này.

20. Những logic nào thường được xử lý trong helper?

Logic trong helper chỉ nên dùng để hỗ trợ hiển thị trên view.

Một cái rất hay được dùng là logic xử lý format hiển thị ngày ở các trang khác nhau.

21. Ruby có cho kế thừa nhiều lớp không?

Ruby không cho phép kế thừa từ nhiều hơn 1 class cha, nhưng cho phép mix module với includeextend.

22. Ruby là strongly hay weakly typed?

Ruby là strongly typed. Sẽ bị lỗi nếu nếu viết kiểu "hello" + 3.

Ngược lại, Javascript là weakly typed, nếu viết kiểu trên thì nó sẽ trả về kết quả "hello3".

23. Bạn đã từng dùng frameworks nào để xử lý background jobs?

  • Delyed::Job: Dễ dàng cài đặt và sử dụng. Hàng đợi nằm trong bảng database. Nếu như dùng chung database cho Delayed::Job và production, sẽ dẫn đến 1 lượng lớn job biến database thành nút cổ chai (bottleneck).
  • Sidekiq: Sử dụng Redis để xử lý hàng đợi. Redis là in-memory data store vì vậy nó rất nhanh. Sidekiq khiến cơ sở hạ tầng (infrastructure) trở nên phức tạp hơn vì phải thêm Redis.
  • Sucker Punch: Chạy như một Ruby process và lưu tất cả job trong bộ nhớ. Job sẽ mất nếu process bị lỗi giữa chừng. Không nên dùng cho các job quan trọng.

24. Cách khai báo một constructor trong class Ruby?

Constructor được định nghĩa thông qua phương thức initialize và được gọi đến khi khởi tạo 1 instance mới của class. Phương thức này không bắt buộc, nó thường được dùng để cung cấp giá trị các thuộc tính cho instance mới.

class Thing
  attr_reader :name
  def initialize(name)
    @name = name
  end
end
t = Thing.new('dog')
puts t.name # => 'dog

25. ActivityRecord là gì?

Active Record là một ORM (object-relational mapping) để nối giữa model và bảng dữ liệu. Nó giúp đơn giản hóa việc xây dựng ứng dụng vì chúng ta sẽ không phải viết SQL để load, save hay xóa đối tượng. Nó cũng cung cấp 1 số cách để tránh SQL injection.

Nguồn: https://medium.com/better-programming/53-ruby-on-rails-interview-questions-and-answers-eb99eed1aeb7


All Rights Reserved