User Tools

Site Tools


inf:ruby:questions

Table of Contents

Ruby theory questions

1. What are Ruby Gems?

This is a very open ended question and you might be better of to start with the basics first:

  • A gem is nothing more than a piece of ruby code packaged as a library so that it can be imported and used by others in their programs,
  • A Ruby gem is therefore simply a library that is written in the ruby programming language,
  • You can add that you often look for ruby gems on rubygems.org. If you have downloaded any recent gems it might be a good idea to mention those.

2. What is the difference between a Symbol and String?

  • Symbols are faster and immutable strings,
  • once a string is used up it is marked for cleaning by the Garbage Collector but it is not cleaned up immediately and it cannot be reused, symbols live for the duration of the session. This leads to increased memory usage however by keeping the symbol alive a bit longer it can be reused again.
    > "string".object_id
    => 5263280 
    > "string".object_id
    => 5220980 
    > "string".object_id
    => 5179720 
    > :symbol.object_id
    => 329128 
    > :symbol.object_id
    => 329128 
    > :symbol.object_id
    => 329128 

    Notice that the object_id stays the same when symbols are created. This happens because the ruby interpreter uses the same heap memory location each time. The symbol was never completely released. In the case of strings the memory is marked for cleanup each time and a new memory is allocated.

  • strings can be modified, symbols are not.

3. What is the purpose of yield?

  • The interpreter essentially invokes a separate piece of code and places it in the location,
  • FIXME

4. What are class variables? How do you define them?

  • Class variables are created using the @@ prefix,
  • It works just like any other variable, however in the case of inheritance it works more like a static variable that is accessed across all variable instances:
    class DemoClass
     @@my_var = nil
      def initialize
        @@my_var = "hello world"
      end
      def my_var
        puts @@my_var
      end
    end
    class Demo2Class < DemoClass
      def initialize
        @@my_var = "goodbye world"
      end
    end
    demo1 = DemoClass.new
    demo1.my_var            # => hello world
    demo2 = Demo2Class.new
    demo2.my_var            # => goodbye world
    demo1.my_var            # => goodbye world
  • FIXME

5. How do you define instance variables?

  • Instance variables are defined using @ symbol,
  • FIXME

6. How do you define global variables?

  • Global variables are defined using $ symbol,
  • it can be declared anywhere and used anywhere, (8-O)
  • it can be used to trigger a procedure if it’s value changes:
    trace_var :$foo, proc{puts "$foo is now #{$foo}"}
    $foo = 7       # => $foo is now 7

7. Does Ruby support constructors? How are they declared?

  • They are declared as the method initialize which is called automatically when object is instanciated:
    class Picture
      def initialize
        puts "In a constructor"
      end
    end
     
    Picture.new
     
    # => In a constructor

8. How can you dynamically define a method body?

  • Instance method can be defined dynamically with Module#define_method(name, body), where name is a method's name and body is a Proc, Method, UnboundMethod or a block literal, allowing methods to be defined at runtime,
    class Conjure
      def self.conjure(name, body)
        define_method(name, body)
      end
    end
     
    Conjure.conjure(:glark, ->{ (3..5).to_a * 2})
    Conjure.new.glark
     
    #=> [3, 4, 5, 3, 4, 5]
  • Module#define_method is a private method so it must be called from within the class the method is being defined on,
  • Alternatively, it can be incoked inside class_eval:
    Array.class_eval do
      define_method(:second, ->{self.[](1)})
    end
     
    [3, 4, 5].second
     
    #=> 4
  • Kernel#define_singleton_method is called to define a singleton method on the receiver:
    Array.define_singleton_method(:second) do |array|
      array[1]
    end
     
    Array.second([2, 3, 4])
     
    #=> 3

FIXME

9. What is a Range?

  • Range is used to declare continuous variables:
    numerical_range = (1..4).to_a
    #=> [1, 2, 3, 4]
     
    character_range = ('bar'..'bat').to_a
    #=> ["bar", "bas", "bat"]
  • it can be iterated like an Array.

10. How can you implement method overloading?

  • Method overloading means multiple methods having the same name but different parameters,
  • no support for this in Ruby,
  • variable number of parameters can be sent to the same method using a hash:
    class MyClass
      def initialize(*args)
        if args.size < 2  || args.size > 3
          puts 'This method takes either 2 or 3 arguments'
        else
          if args.size == 2
            puts 'Found two arguments'
          else
            puts 'Found three arguments'
          end
        end
      end
    end
     
    MyClass.new([10, 23], 4, 10)  
    #=> Found three arguments
    MyClass.new([10, 23], [14, 13]) 
    #=> Found two arguments

11. What is the difference between ''&&'', ''and'' and '&'?

  • First two are both logical AND statements,
  • && has higher precedence than and:
    foo = 3
    bar = nil
    a = foo and bar
    # => nil
    a
    # => 3
     
    a = foo && bar
    # => nil
    a
    # => nil

    Acts like (a = foo) and bar, and has lower precendence than =,

  • & operator works differently depending on the context:
    • Bitwise AND is boolean AND for each bit:
      14 & 13
      => 12
      # 1110 & 1101 = 1100 (in binary)

FIXME: http://ablogaboutcode.com/2012/01/04/the-ampersand-operator-in-ruby/

12. How can you create setter and getter methods in Ruby?

Method Effect
attr_reader :v def v; @v; end
attr_writer :v def v=(value); @v=value; end
attr_accessor :v attr_reader :v; attr_writer :v

13. What is the convention for using ‘!’ at the end of a method name?

  • ! indicates that the method is destructive in some way (for example it changes the object itself)

14. What is a module?

  • Module is like a class, but it can't be instantiated or subclassed,

FIXME

15. Does Ruby support multiple inheritance?

  • Nope. But Ruby offers a technique called mixin. Modules can be mixed-in with the class in which they are imported:
    module Logger
      def log(msg)
        puts "Message: #{msg} from #{self.to_s}"
      end
    end
     
    class Program
      include Logger
    end
     
    ph = Program.new
    ph.log("Hello!")
     
    #=> Message: Hello! from #<Program:0x00000001d11e28>

16. How will you implement singleton pattern?

  • The goal of singleton pattern is to write a class definition that only allows the creation of single instance of that class,
  • singleton pattern is commonly used with database drivers or loggers, where only one instance is allowed,
  • Ruby Standard Library includes a module called Singleton:
    require 'singleton'
     
    class Logger
      include Singleton
     
      def log(msg)
        puts(msg)
      end
    end
     
    Logger.instance.log("Test message")
    #=> Test message
    Logger.new.log("Will it work?")
    #=> singleton.rb:12:in `<main>': private method `new' called for Logger:Class (NoMethodError)

17. How will you implement an observer pattern?

  • Observer pattern means that object (subject) maintains a list of its dependents (observers) and notifies them automatically of any state changes,
  • it is mainly used to implement distributed event handling systems,
  • Ruby Standard Library already includes a module that implements Observer pattern:
    require 'observer'
     
    # Periodically fetch stock price
    class Ticker
      include Observable
     
      attr_accessor :price
     
      def initialize(symbol, price)
        @symbol = symbol
        @price = price
      end
     
      def run
        last_price = nil
        loop do
          @price = @price + Random.rand(11)
          puts "Current price: #{price}"
          unless @price == last_price
            # Notify observers
            changed
            last_price = @price
            notify_observers(Time.now, @price)
          end
        end
      end
    end
     
    # All Warners are observers
    class Warner
      def initialize(ticker)
        ticker.add_observer(self)
      end
    end
     
    class SMSAlert < Warner
      def update(time, price)
        puts "--- #{time.to_s}: SMS Alert for price: #{price}"
      end
    end
     
    class EmailAlert < Warner
      # Callback for observer
      def update(time, price)
        puts "+++ #{time.to_s}: Email Alert Price changed to #{price}"
      end
    end
     
    ticker = Ticker.new("MSFT", 307)
    SMSAlert.new(ticker)
    EmailAlert.new(ticker)
    ticker.run
     
    #=> Current price: 317
    #=> --- 2013-06-11 19:28:21 +0200: SMS Alert for price: 317
    #=> +++ 2013-06-11 19:28:21 +0200: Email Alert Price changed to 317
    #=> Current price: 323
    #=> --- 2013-06-11 19:28:21 +0200: SMS Alert for price: 323
    #=> +++ 2013-06-11 19:28:21 +0200: Email Alert Price changed to 323
    #=> Current price: 332
    #=> --- 2013-06-11 19:28:21 +0200: SMS Alert for price: 332
    #=> +++ 2013-06-11 19:28:21 +0200: Email Alert Price changed to 332

18. How can you define a constant?

19. How can you define an Exception?

20. What is the default access modifier for a method? What are the differences between access modifiers?

21. How does .map() and .reduce() work in Ruby? What about .map(&:downcase) ?

  • map goes through each element in a collection and replaces it with the value returned from a block of code,
  • reduce accumulates a value across the members of a collection,
  • by using .map(&xxx) syntax, you're telling Ruby to pass the Proc object held in xxx to map method as a block.If xxx is not a Proc object, Ruby tries to coearce it into one by sending it a to_proc message. If a symbol is passed, to_proc is called on the symbol. This method would look like so if it was implemented in Ruby:
    def to_proc
      proc {|obj, *args| obj.send(self, *args) }
    end
  • using short syntax like this is half as fast as the more explicitly coded block.

What is new in Ruby 2.0?

  • Bitmap Garbage Collection,
  • require() speed improvements,
  • keyword arguments,
    def foo(foo: 'bar', baz: 'qux', **rest)
      # Do something
    end
     
    foo(baz: 'qux', foo: 'frob')
  • module prepend:
    module IncludableModule
      def something; end
    end
     
    class MyClass
      prepend IncludableModule
    end
  • lazy enumerators:
    to_infinity = (0..Float::Infinity)
    beyond = to_infinity.lazy.select do |n|
      num % 42 == 0
    end
     
    100.times do {|n| puts beyond.next }
  • tracepoint, object oriented alternative to set_trace_func:
    trace = TracePoint.new(:raise) do |t|
      puts "Alert: Exception raised!"
    end
     
    trace.enable
  • refinements, localised and contained monkey patching:
    module MyString
      refine String do
        def palindrome?
          self == self.reverse
        end
      end
    end
     
    using MyString # Monkey patch now active for context
  • literal symbol lists: %i{eeny meeny miny moe},
  • binary search: (1..9999999).bsearch(12345)
  • source code in utf-8 by default,
  • DIR, shows absolute path to file's directory,
  • .to_h, useful for converting Structs.

TODO: http://magazine.rubyist.net/?Ruby200SpecialEn

What is new in Ruby 2.1?

Frozen String Literals

  • Strings in ruby are mutable, so each time a string is modified, a new String object is created,
  • if you want to compare user input to a symbol, you either will have to convert symbol to string (additional string creation) or string to symbol (DoS attack, since they are not garbage collected),
  • Strings can be frozen, preventing changes done to it:
    MAREK = "Marek".freeze
     
    def marek?(name)
      name == MAREK
    end

    or, in Ruby 2.1:

    def marek?(name)
      name == "marek"f
    end

Required Keyword Arguments

  • Keyword Arguments were added in Ruby 2.0:
    def foo(a: 10)
      puts a
    end
     
    foo(a: 20) # => 20
    foo        # => 10
  • this always needs default value. In Ruby 2.1, you can have required keyword arguments:
    def foo(a:)
      puts a
    end
     
    foo(a: 20) # => 20
    foo        # => ArgumentError: missing keyword: a

Method definition returns method name

# Ruby 2.0
def foo() end # => nil
 
# Ruby 2.1
def foo() end # => :foo

Useful for metaprogramming.

Remove garbage bytes from Strings

"abc\u3042\x81".scrub("*") #=> "abc\u3042*"

Others

  • Partially generational GC,

SEE: https://github.com/ruby/ruby/blob/v2_1_0/NEWS

23. What are the differences between Proc, lambda and block?

  • Blocks, Procs and lambdas are all closures. This means that they hold the values of any variables that were around when they were created.

Blocks

  • Block is a code that is implicitly passed to a method through the use of either curly braces ({…}) or do…end syntax,
  • yield defers the execution of the calling method in order to evaluate the block; the result of the block, if any, is then evaluated by any remaining code in the method; yield accepts parameters, which are then passed into and evaluated within the block,
  • calling yield will execute the code within the block provided to the method,
  • single use, can't be assigned to a variable,
  • can only send one block to a method, but multiple Procs (in an Array for example),

Procedures

  • Can be used to store blocks of code. Then, they can be passed to any method that accepts a callable object,

Lambdas

  • Almost identical to Procs, but lambda checks the number of arguments it receives and returns ArgumentError if they don't match,
  • can also be used to create lambdas,
  • it provides diminutive returns, meaning it returns its value and allows method to continue, while Procs stop the method execution:
    def lambda_return
      lambda {return "I'm a lambda!"}.call
      return "Still running after lambda!"
    end
     
    def proc_return
      Proc.new {return "I'm just a Proc. :-("}.call
      return "Still running after proc!"
    end
     
    puts lambda_return
    puts proc_return
  • lambdas conceptually work like methods, they enforce correct number of arguments and do not override the calling methods return, Procs are more like drop-in code snippets,
  • in Ruby, arguments cannot have a return keyword in them, so a Proc with return passed into a method would give a LocalJumpError, but a lambda acts like a method, and this in turn can have return in it:
    def generic_return(code)
      one, two    = 1, 2
      three, four = code.call(one, two)
      return "Give me a #{three} and a #{four}"
    end
     
    puts generic_return(lambda { |x, y| return x + 2, y + 2 })
    puts generic_return(Proc.new { |x, y| return x + 2, y + 2 })
    puts generic_return(Proc.new { |x, y| x + 2; y + 2 })
    puts generic_return(Proc.new { |x, y| [x + 2, y + 2] })
     
    # => Give me a 3 and a 4
    # => unexpected return (LocalJumpError)
    # => Give me a 4 and a
    # => Give me a 3 and a 4
  • we can pass methods as an argument to other methods with the use of method keyword:
    class Array
      def iterate!(code)
        self.each_with_index do |n, i|
          self[i] = code.call(n)
        end
      end
    end
     
    def square(n)
      n ** 2
    end
     
    array = [1, 2, 3, 4]
     
    array.iterate!(method(:square))
     
    puts array.inspect
     
    # => [1, 4, 9, 16]

INFO:

24. Describe Ruby data structures and their advantages.

Array

  • holds a collection of object references,
  • each object reference occupies a position in the array, identified by a non-negative integer index,
  • with the use of pop and push, Array can be treated like a stack,
  • with the use of push and shift, Array can be used like a first-in first-out (FIFO) queue,

Hash (or associative array, map, dictionary)

  • indexed collections of object references,
  • index can by any object, not just Integer
  • storing value in a Hash means storing two things: index (the key) and the value,
  • Ruby remembers the order in which items were added to a hash,

Set

  • implements a collection of unordered values with no duplicates,
  • a hybrid of Hash's fast lookup and Array's intuitive inter-operation,
  • the equality is determined according to Object#eql? and Object#hash since Set uses Hash as storage,
  • no fixed ordering, so no ability to access elements by index,

Useful when:

  • need an array with no duplicate values,
  • useful to find out if two differently sorted arrays are equal

INFO: http://spin.atomicobject.com/2012/09/04/when-is-a-set-better-than-an-array-in-ruby/

Struct

  • is something between hashes and classes,
  • needs to have its attributes defined when you create it,
  • both Struct and OpenStruct imply more concrete relationship amongst the data than Hash, but they don't have the instance methods as would Class,
  • faster than OpenStruct, take less memory,

Use case:

  • you need a data container and fields are fixed and known beforehand (i.e. at time of writing of the code),
  • you need a structured Hash key,
  • you want to quickly define a class with a few fields,
  • you need to detect errors caused by misspelled field names.

OpenStruct

25. What is the difference between equal?, eql?, ===, and == ?

  • ==, a generic “equality”, at Object level, it only returns true if compared objects are the same object. This method is typically overridden in descendant classes to provide class-specific meaning,
  • ===, a case equality, at Object level it effectively is the same as calling #==, it is typically overriden to provide meaningful semantics in case statements,
  • eql? - generic equality, returns true if compared objects have the same value. Used by Hash to test members for equality. For objects of class Object, eql? is synonymous with ==,
  • equal? - identity comparison, this should never be overriden, it is used to determine object identity (a.equal?(b) iff a is the same object as b).

Rails specific questions

1. Explain Rails MVC implementation.

  • MVC (model, view, controller) architecture is at the core of Rails,
  • benefits:
    • isolation of business logic from the user interface,
    • ease of keeping code dry,
    • makes it clear where different types of code belong for easier maintenance,
  • model represents the information (data) of the application and the rules to manipulate that data. In case of Rails, models are primarily used for managing the rules of interaction with a corresponding database table. Most of application's business logic will be there,
  • views represent the user interface of the application, views handle the job of providing data to the web browser or other tool that is used to make requests from the application,
  • controllers glue models and views; are responsible for processing the incoming requests from the wbe browser, interrogating the models for data and passing that data on to the views for presentation.

2. What is a scope?

  • Scopes are nothing more than SQL fragments. By using these fragments one can cut down on having to write long queries each time you access content.

3. What deployment tools do you know? How do they work?

  • Capistrano is a popular deployment tool. It allows you to copy code from your source control repository to your server via SSH and perform pre and post-deploy functions like restarting a webserver, busting cache, renaming files, running database migrations and so on. It is also possible to deploy to many machines at once.

More info:

4. How can you migrate your database schema one level down?

rake db:rollback
rake db:rollback STEP=1
 
# Rollback to the beginning
rake db:reset
 
# or if you're not worried about data
rake db:purge

5. What is a sweeper?

  • Sometimes you want to have control over how often and when the cache expires,
  • sometimes it is a good idea to have the system determine that on a logical basis,
  • Say you have a list of product on your site and you want to reload the cache each time a new product is added/updated/deleted, then you can achieve this by using the sweeper:
    class ProductSweeper < ActionController::Caching::Sweeper
      observe Product# This sweeper is going to keep an eye on the Product model 
     
      # If our sweeper detects that a Product was created call this
      def after_create(product)
        expire_cache_for(product)
      end
     
      # If our sweeper detects that a Product was updated call this
      def after_update(product)
        expire_cache_for(product)
      end
     
      # If our sweeper detects that a Product was deleted call this
      def after_destroy(product)
        expire_cache_for(product)
      end
     
      private
     
        def expire_cache_for(product)
          # Expire the index page now that we added a new product
          expire_page(:controller => 'products', :action => 'index')
          # Expire a fragment
          expire_fragment('all_available_products')
        end
     
    end

6. How can you implement caching in Rails?

  • Fragment caching gives you the choice to fragment to pull a portion from the cache and the remaining from a real-time DB call. Say you wanted to show all the orders placed on your website in real time and didn’t want to cache that part of the page, but did want to cache the part of the page which lists all products available, you could use this piece of code:
    <% Order.find_recent.each do |o| %>
      <%= o.buyer.name %> bought <%= o.product.name %>
    <% end %>
    <% cache do %>  All available products:
      <% Product.all.each do |p| %>
        <%= link_to p.name, product_url(p) %>
      <% end %>
    <% end %>
  • Page caching is often used for home pages and is super fast:
    class ProductsController < ActionController
      caches_page:index
     
      def index
        @products = Products.all
      end
    end

7. What is a filter? When it is called?

  • Filters are methods that are called either before or after a controller action is called.

8. What is RESTful routing?

REST is a set of principles that define how Web standards, such as HTTP and URIs, are supposed to be used (which often differs quite a bit from what many people actually do). The promise is that if you adhere to REST principles while designing your application, you will end up with a system that exploits the Web’s architecture to your benefit. In summary, the key principles are:

  • using resource identifiers such as URLs to represent resources,
  • transferring representations of the state of that resource between system components
  • Give every “thing” an ID
  • Link things together
  • Use standard methods
  • Resources with multiple representations
  • Communicate statelessly

9. What is the purpose of layouts?

10. Is it possible to embed partial views inside layouts?

11. How can you create a REST API for your application?

12. How can you define a new environment called 'staging'?

13. What is the difference between has_one and belongs_to?

14. What is a has and belongs to many association?

15. How can you implement single table inheritance?

  • ActiveRecord allows inheritance by storing the name of the class in a column that by default is named type,
  • you then can create models like so:
    class Company < ActiveRecord::Base; end
    class Firm < Company; end
    class Client < Company; end
    class PriorityClient < Client; end

    When you do Firm.create(name: “sqTech”), this record will be saved in the companies table with type Firm,

  • if you have many fields in the table that are not shared by all types, STI may be not the best direction,

16. What is a polymorophic association?

17. What is eager loading?

18. How does validation work?

19. Why is fields_for used for?

20. What is the purpose of a helper method?

21. What is flash?

22. How can you implement internationalization?

23. What is and how can you implement a state machine?

24. How can you upload a file to a server?

25. How can you show SEO friendly URLs instead of using only numeric IDs?

26. Is Rails scalable?

Yes Rails gives you complete freedom to use all traditional means of scaling an application. Things like memcached, caching full pages, caching fragments are all supported.

You can use any standard CDN to serve your media and static content as well.

Database scaling using sharding is supported.

Finally heroku makes your life easier by giving you the flexibility to scale up/down based on your need. Mostly websites have a peak time during which you need more servers and then there is a sleep time. Heroku makes that on-demand scaling process simpler. Companies such as HireFireApp.com makes the autoscale process easier.

27. What are the key deployment challenges?

  • mismatched gem version sbetween local and production environments

28. How can you secure a rails application?

  • Common web security issues involve SQL Injection, Cross-Site Scripting (XSS) and session fixation/hijacking.

TODO: http://guides.rubyonrails.org/security.html

SQL injection

Use:

User.where("login = ? AND password = ?", entered_user_name, entered_password).first
# or
User.where(:login => entered_user_name, :password => entered_password).first

instead of:

User.first("login = '#{params[:name]}' AND password = '#{params[:password]}'")

because of:

SELECT * FROM users WHERE login = '' OR '1'='1' AND password = '' OR '2'>'1' LIMIT 1 

29. How can rails engage with a SOA platform?

30. What kinds of associations are available in ActiveRecord

  • Association is a connection between two ActiveRecord models,
  • associations are implemented with macro-style calls so it is possible to add features to the models declaratively,
  • Rails supports six types of associations:
    • belongs_to
    • has_one
    • has_many
    • has_many :through
    • has_one :through
    • has_and_belongs_to_many
  • all association methods are build around caching, which keeps the result of the most recent query available for further operations, the cache is even shared across methods:
    customer.orders                 # retrieves orders from the database
    customer.orders.size            # uses the cached copy of orders
    customer.orders.empty?          # uses the cached copy of orders
  • passing true to the assocition call will reload the cache:
    customer.orders                 # retrieves orders from the database
    customer.orders.size            # uses the cached copy of orders
    customer.orders(true).empty?    # discards the cached copy of orders
                                    # and goes back to the database
  • by default, ActiveRecord doesn't know about the connection between associations. This can lead to two copies of an object getting out of sync:
    class Customer < ActiveRecord::Base
      has_many :orders
    end
     
    class Order < ActiveRecord::Base
      belongs_to :customer
    end

    This happens because c and o.customer are two different in-memory representations of the same data, and neither one is automatically refreshed from changes to the other. Active Record provides the :inverse_of option so that you can inform it of these relations. It won't work with: through, polymorphic, as associations. For belongs_to associations, has_many inverse associations are ignored.

belongs_to

  • sets up a one-to-one connection with another model meaning that each instance of declaring model “belongs to” one instance of another model,
  • on this side, foreign key is set,

has_one

  • sets up one-to-one connection with another model, similarily to belongs_to but with different semantics,
  • it indicates, that each instance of a model contains or possesses one instance of another model,
  • the foreign key is set on target model,

has_many

  • indicates one-to-many connection with another model, meaning that each instance of the model has zero or more instances of another model,

has_many :through

  • sets up many-to-many connection with another model, meaning that the declaring model can be matched with zero or more instances of another model by proceeding through a third model,
  • automatic deletion of join model is direct, no destroy callbacks are triggered,
  • useful for setting up shortcuts through nested has_many associations,
  • if you need validations, callbacks or extra attributes on the join model, you should use this instead of has_and_belongs_to_many,

has_one :through

  • sets up one-to-one connection with another model, meaning that the declaring model can be matched with one instance of another model by proceeding through a third model,

has_and_belongs_to_many

  • creates direct many-to-many connection with another model, without intervening model,
  • if you don't need to do anything with the relationship model, it might be simplier to set up this than has_many :through,
  • you need to remember to create the joining table in the database,

Polymorphic association

  • a model can belong to more than one other model, on a single association,
  • you need to declare both a foreign key column and a type column in the model that declares the polymorphic interface,

Self joins

  • sometimes a model should have a relation to itself,
  • example: all employees in a single database model, but you want to trace relationships such as between a manager and his subordinates:
    class Employee < ActiveRecord::Base
      has_many :subordinates, :class_name => "Employee",
        :foreign_key => "manager_id"
      belongs_to :manager, :class_name => "Employee"
    end

31. Advantages of NoSQL (MongoDB) databases over SQL

  • has no formally described tables, stores structured data in JSON like documents with dynamic schemas - columns with no values will be set as NULL in SQL wasting space, while in NoSQL they won't,
  • querying works by passing a document explaining what needs to be queried - no parsing is necessary, no need to worry about injection attacks,
  • no support for JOINs in NoSQL, but documents can be embedded within another document,
  • no support for transactions,
  • MongoDB supports master-slave replication with automated failover and built-in horizontal scaling via automated range-based partitioning,
  • MongoDB scales horizontally using sharding. Developer selects a shard key, which determines how the data in a collection will be distributed. The data is split into ranges (based on the shard key) and distributed across multiple shards. (A shard is a master with one or more slaves.)
  • MapReduce ( Map() procedure that performs filtering and sorting (such as sorting students by first name into queues, one queue for each name) and a Reduce() procedure that performs a summary operation (such as counting the number of students in each queue, yielding name frequencies). The “MapReduce System” (also called “infrastructure”, “framework”) orchestrates by marshaling the distributed servers, running the various tasks in parallel, managing all communications and data transfers between the various parts of the system, providing for redundancy and failures, and overall management of the whole process) can be used for batch processing of data and aggregation operations. The aggregation framework enables users to obtain the kind of results for which the SQL GROUP BY clause is used,
  • JavaScript can be used in queries, aggregation functions (for example MapReduce) are sent directly to the database to be executed,

32. What is new in Rails 4.0?

  • Strong parameters - instead of attr_accessible in model, we use params.requir(:model).permit(:name, :email), it protects you from unexpected mass assignment,
  • Turbolinks - in browsers with pushState support, clicking a link causes an AJAX request, updates the URL with pushState (so back button works) and uses JS to update the <title> and the <body> in the DOM, so no CSS and JS are needed to be redownloaded; with Turbolinks page load events won't fire when user navigates from page to page, because DOM never actually reloads, so new events are added (fetch, change, load, restore),
  • Russian doll caching, nested fragment caching:
    class Milestone < ActiveRecord::Base
      has_many :todos
    end
     
    class Todo < ActiveRecord::Base
      belongs_to :milestone, :touch => true
    end
     
    # app/views/milestones/show.html.erb
    <% cache @milestone do %>
      <h1><%= @milestone.name %></h1>
      <div class="description"><%= @milestone.description %></div>
     
      <ul class="todos">
        <%= render @milestone.todos %>
      </ul>
    <% end %>
     
    # app/views/todos/_todo.html.erb
    <% cache todo do %>
      <li class="todo">
        <%= todo.description %>
        <span class="status"><%= todo.status %></span>
      </li>
    <% end %>

    :touch option is required for this caching stratego to work properly. If a Todo is added to a milestone, we need to break cache on the milestone to avoid serving stale views. Suppose we have amilestone with ten todos. Editing only one todo causes the milestone's cache to break, but when generating the HTML, all but one of the todo partials can be fetched from the cache, improving render times. We're trading time for space, as this generates a lot of cruft in our cache,

  • Straming, through ActionController::Live - new module provides the ability to stream data to clients, this needs a threaded server (thin, puma) so that stream data actioms from streaming controllers run in a separate thread,
  • Article.all is now ActiveRecord::Relation - lazy loaded,
  • Article.none returns Relation with no records,
  • Article.load will trigger the SQL query but will return a relation - useful if we want to execute the query for caching behaviour but still need a relation,
  • it is possible to call not on a where scope to invert it:
    >> Article.where.not(name: "Hello")
      Article Load (107.6ms)  SELECT "articles".* FROM "articles" WHERE ("articles"."name" != 'Hello')
  • order clause now accepts a hash,
  • find_by method which works like find_by_something but doesn't rely on method_missing and is faster:
    >> Article.find_by name: "Hello"
  • ActiveModel::Model - works like ActiveRecord model but without the database stuff, we can add validations, attr_accessors,
  • update action now responds to either PUT or PATCH request,
  • controllers and models directories now have a concerns directory. It is designed for modules that we can include in our models to help reduce their size,
  • collection_check_boxes and collection_radio_buttons helper methods to generate lists of checkboxes or radio buttons for an association,
  • supplying constraints to a route will make them default attributes when generating the URL:
    get 'foo', to: 'articles#index', constraints: {protocol: "https", subdomain: "test"}
     
    >> app.foo_url
    => "https://test.example.com/foo"
  • New PostgreSQL features:
    • hstore

33. What is the difference between _path and _url route helpers?

_url methods generate entire URL, including protocol and domain, _path generates just the path part.

20.

General object-oriented and programming questions

1. What is polymorphism?

  • formally, it is the ability to create an object that has more than one form,
  • the purpose of polymorphism is to implement a message-passing style of programming, where objects of various types define a common interface of operations for user,
  • primary usage in industry is the ability of objects belonging to different types to respond to method, field or property calls of the same name, each one according to an appropriate type-specific behavior,
  • one way to achieve this kind of behavior is through inheritance:
    class Bird
      def initialize(name)
        @name = name
      end
     
      def speak
        puts 'Tweet'
      end
     
      def fly
        puts 'Up up and away...'
      end
    end
     
    class Duck < Bird
      def speak
        puts "Quack I am #{@name}"
      end
    end
     
    class Penguin < Bird
      def speak
        puts "Squak I am #{@name}"
      end
     
      def fly
        puts 'Nope. I swim...'
      end
    end

    And now we can do something like this:

    birds = [Bird.new('Tweetie'), Duck.new('Donald'), Penguin.new('Mumbo')]
    birds.each do |b|
      b.fly
    end
     
    # Up up and away...
    # Up up and away...
    # Nope. I swim...
     
    birds.each do |b|
      b.speak
    end
     
    # Tweet
    # Quack I am Donald
    # Squak I am Mumbo
  • in Ruby, duck typing is preferred to this kind of inheritance polymorphism. “If it walks like a duck and quacks like a duck, then it is a duck”. We do this like so:
    class Duck
      def speak
        puts "Quack I am #{@name}"
      end
     
      def fly
        puts 'Up up and away...'
      end
    end
     
    class Penguin
      def speak
        puts "Squak I am #{@name}"
      end
     
      def fly
        puts 'Nope. I swim...'
      end
    end

    We put any shared methods in a module and then include them in our classes:

    module Bird
      def initialize(name)
        @name = name
      end
    end
     
    class Duck
      include Bird
      ...
    end
     
    class Penguin
      include Bird
      ...
    end

http://www.runtime-era.com/2012/08/polymorphism-in-ruby.html

2. What are SOLID principles?

  • Single Responsibility Principle,
  • Open for extension, closed to modification,
  • Liskov Substitution Principle,
  • Interface Segregation,
  • Dependency Inversion.

Single Responsibility Principle

Open for extension, closed to modification

Liskov Substitution Principle

Interface Segregation

Dependency Inversion

Algorithm and data structure questions

1. Reverse an interger, e.g. 12345 => 54321, without converting to a string.

def get_number_digits(number)
  digits = []
  modulo = 1
  loop do
    modulo *= 10
    digits << (number % modulo) / (modulo / 10)
    break if number < modulo
  end
  digits
end
 
def assemble_digits(ary)
  number = 0
  multiplier = 1
  ary.reverse.each do |digit|
    number += digit * multiplier
    multiplier *= 10
  end
  number
end
 
digits = get_number_digits(1923434)
assemble_digits(digits)

2. Peform a binary search on an array of numbers to find a number.

ARRAY = [1, 1, 1, 1, 5, 6, 8, 9, 10, 11]
 
def binary_search(ary, number)
  low_index   = 0
  high_index  = ary.size - 1
 
  while low_index <= high_index
    mid_index = (low_index + high_index) / 2
    value     = ary[mid_index]
    if value < number
      low_index = mid_index + 1
    elsif value > number
      high_index = mid_index - 1
    else
      return mid_index
    end
  end
  nil
end
 
puts binary_search(ARRAY, 1)

Notes:

  • With duplicates, it will return first one found, not neccesarily the lowest indexed one,
  • array needs to be sorted,

3. What data structures are you familiar with?

  • Queue - entities in the collection are kept in order and the principal (or only) operations on the collection are the addition of entities to the rear terminal position, known as enqueue, and removal of entities from the front terminal position, known as dequeue. This makes the queue a First-In-First-Out (FIFO) data structure. In a FIFO data structure, the first element added to the queue will be the first one to be removed. This is equivalent to the requirement that once a new element is added, all elements that were added before have to be removed before the new element can be removed. Often a peek or front operation is also implemented, returning the value of the front element without dequeuing it. A queue is an example of a linear data structure, or more abstractly a sequential collection,
  • Stack - principal (or only) operations on the collection are the addition of an entity to the collection, known as push and removal of an entity, known as pop.[1] The relation between the push and pop operations is such that the stack is a Last-In-First-Out (LIFO) data structure. In a LIFO data structure, the last element added to the structure must be the first one to be removed. This is equivalent to the requirement that, considered as a linear data structure, or more abstractly a sequential collection, the push and pop operations occur only at one end of the structure, referred to as the top of the stack. Often a peek or top operation is also implemented, returning the value of the top element without removing it,

4. Fibonacci

# From https://github.com/mruby/mruby/blob/master/benchmark/fib39.rb
def fib n
  return n if n < 2
  fib(n-2) + fib(n-1)
end
 
puts fib(39)

Real Questions

1. What kind of SQL Joins you know?

  • Cross join - each row from first table with each row from second table:
    # explicit
    SELECT *
    FROM employee CROSS JOIN department;
     
    # implicit
    SELECT *
    FROM employee, department;
  • Inner join - compares each row from first table with each row of second table to find all pairs of rows which satisfy the join-predicate. When it is, column values for each matched pair of rows from first and second table are combined into a result row:
    # explicit
    SELECT *
    FROM employee INNER JOIN department
      ON employee.DepartmentID = department.DepartmentID;
     
    # implicit
    SELECT *
    FROM employee, department
    WHERE employee.DepartmentID = department.DepartmentID;
  • Equi-join - similar to Inner join, but only equality comparisons can be used in the join-predicate,
  • Natural join - compares all columns in both tables that have the same column names in the joined tables, the resulting table contains only one column for each pair of equally named columns. The use of this join is discouraged (a column is inadvertently added with the name that exists in other table):
    SELECT *
    FROM employee NATURAL JOIN department;
  • Left outer join - always contains all records of the “left” table (first), even if the join-predicate does not find any matching record in the “right” table (second). In such case, fields from right table are filled with NULL:
    SELECT *
    FROM employee LEFT OUTER JOIN department
      ON employee.DepartmentID = department.DepartmentID;
  • Right outer join - reversed left outer join:
    SELECT *
    FROM employee RIGHT OUTER JOIN department
      ON employee.DepartmentID = department.DepartmentID;
  • Full outer join - combines left outer join and right outer join, returning all rows:
    SELECT *
    FROM employee FULL OUTER JOIN department
      ON employee.DepartmentID = department.DepartmentID;
  • Self-join - joins a table to itself:
    SELECT F.EmployeeID, F.LastName, S.EmployeeID, S.LastName, F.Country
    FROM Employee F INNER JOIN Employee S ON F.Country = S.Country
    WHERE F.EmployeeID < S.EmployeeID
    ORDER BY F.EmployeeID, S.EmployeeID;

2. What is oAuth?

3. Find highest singular number from a given range.

4. What kind of HTTP actions do you know? How Rails uses them?

There are several described in RFC2616 for HTTP/1.1:

  • OPTIONS allows the client to determine the options and/or requirements associated with a resource, or the capabilities of a server, without implying a resource action or initiating a resource retrieval,
  • GET means retrieve whatever information (in the form of an entity) is identified by the Request-URI,
  • HEAD is identical to GET except that the server MUST NOT return a message-body in the response,
  • POST is used to request that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line,
  • PUT requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server,
  • DELETE requests that the origin server delete the resource identified by the Request-URI,
  • TRACE is used to invoke a remote, application-layer loop-back of the request message,
  • CONNECT method is reserved for use with a proxy that can dynamically switch to being a tunnel.
HTTP Verb Path Action
GET /photos index
GET /photos/new new
POST /photos create
GET /photos/:id show
GET /photos/:id/edit edit
PATCH/PUT /photos/:id update
DELETE /photos/:id destroy

5. How Rails simulates HTTP actions other than POST and GET?

Forms in web browsers can only send POST and GET requests. Any other request (PUT, DELETE) is send as a POST request with a hidden field called _method, set either to put or delete. Rails application detects it and route the request to update or destroy action respectively.

6. What is AJAX? What is it used for and what are the limitations of AJAX?

  • AJAX, (Asynchronous JavaScript and XML), is a set of technologies, that allow an interaction with user to be made without complete page reload,
  • relies on XMLHttpRequestObject, XHR, API available in all modern browsers, that allows JavaScript code on the browser to exchange data with the server and use it to change the user interface of the application on the fly, without a page refresh,
  • some people block the use of JavaScript (slow computer) and those elements of a web application will be inaccessible to them
  • traditional “Back/Forward” browser navigation is no longer possible,
  • JSON (JavaScript Object Notation) is commonly used in AJAX as a “language-independent, compact, human-readable and versatile data format”, it supplies an easy way to encode JavaScript objects,
  • JSONP (JSON with padding) provides a method to request data from a server in a different domain, something prohibited by typical web browsers because of the same origin policy.

7. How would you implement Ruby Object#tap() method? How does it work?

class Object
  def tap
    yield self
    self
  end
end

It allows you do do something with an object inside of a block, and always have that block return the object itself.

INFO: http://www.seejohncode.com/2012/01/02/ruby-tap-that/

8. What is the difference between include and extend?

  • include makes the module's methods available to the instance of a class, included module is added as a superclass of the class being defined:
    module Logger
      def log(msg)
        STDERR.puts Time.now.strftime("%H:%M:%S: ") + "#{self} (#{msg})"
      end
    end
     
    class Song
      include Logger
    end
     
    s = Song.new
    s.log("created")
  • extend makes the methods available to the class itself:
    module Humor
      def tickle
        "#{self} says hee, hee!"
      end
    end
     
    obj = "Grouchy"
    obj.extend Humor
    obj.tickle # => "Grouchy says hee, hee!"

9. What is the difference between .find and .find_by_id in Rails?

  • .find, if passed an ID or array of ID's will try to find them all. Failing that, it will raise an exception,
  • .find_by_id is a dynamically generated method (hence slower) and if it doesn't find given records, returns nil.

10. What is the difference between after_commit and after_safe callback?

11. What is pJax?

12. If a class inherits from another class and a module, and they all have the same method, how the inheritance chain will look like?

How do you evaluate a gem for production environment?

There are a couple of criteria that should be considered when evaluating a gem:

  • test coverage,
  • scalabilty,
  • popularity,
  • extendibility,
  • frequent updates.

How a singleton pattern is implemented in Ruby?

This is achieved by:

  • making Klass.new and Klass.allocate private,
  • overriding Klass.inherited(sub_klass) and Klass.clone() to ensure that the Singleton properties are kept when inherited and cloned,
  • providing the Klass.instance() method that returns the same object each time it is called,
  • overriding Klass._load(str) to call Klass.instance(),
  • overriding Klass#clone and Klass#dup to raise TypeErrors to prevent cloning or duping.

How is a Observer pattern implemented in Ruby?

Source

IRC

20:36 < jastix> sqbell: i was asked this kind of question only once. I was asked to think how to sort an array.

20:36 < dhoss> sqbell: do you know anything about basic data structures? sorting, searching trees, etc

20:36 < terrellt> sqbell: I'm not sure what they'd ask. If they're trying to find someone with a classic CS degree you're looking at hash tables, linked lists, dynamic arrays. Sorting algorithms. Most of that's 
                  dealt with in Ruby though.

20:37 < terrellt> Search trees are potentially useful in Rails land. Hash tables too.

20:38 < brownies> sqbell: at a bare minimum you should know your way around Hashes and Arrays (duh) and i'd also like to see knowledge of handy Ruby things like OpenStruct

20:39 < brownies> sqbell: from there it really depends on who is interviewing you and the company, but i would be mildly satisfied if you could then go on to talk about calling #map and #reduce on both of those 
                  things and how those work, and maybe i would make you write some basic algorithms using those methods

20:37 < joshuawscott> sqbell: if it's a Rails position, you'll likely be asked what you don't like about RoR.

20:40 < brownies> and perhaps since it's an RoR position that's a nice segue into talking about activeRecord things and DB structures

20:42 < jastix> sqbell: often people ask about fibonacci numbers and prime numbers

20:43 < joshuawscott> sqbell: http://codility.com/train/ is a good place to see what you don't know
inf/ruby/questions.txt · Last modified: 2021/02/16 09:56 (external edit)