Skip to content

Instantly share code, notes, and snippets.

@achasveachas
Last active August 23, 2017 15:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save achasveachas/892d6467d75c05a4b37b30cc6cadcb16 to your computer and use it in GitHub Desktop.
Save achasveachas/892d6467d75c05a4b37b30cc6cadcb16 to your computer and use it in GitHub Desktop.
### Ruby ###

###
# 1. Which method is best, and why?
###


# A
def empty?(s)
  raise ArgumentError, "s must be a String" unless s.is_a? String
  s.size == 0
end

# B
def empty?(s)
  raise ArgumentError, "s must respond to 'size'" unless s.respond_to? :size
  s.size == 0
end

# C
def empty?(s)
  s.size == 0
end

Answer: The answer to any "Which X is best?" is usually "best for what?" Option A seems to be best if the #empty? method is only checking for empty strings; it has a nice helpful error message (though I might change it from saying that "'s' (the name of a local variable) must be a string" to something like "You must pass a String in as an argument" or something like that. Someone using the method doesn't need to know the method uses 's' as a local variable).

B and C are better options if you are looking at more than just strings (like Ruby's real life .empty? method). B has the advantage over C in that it throws a more helpful error message. C would just through an "undefined method 'size' for X", which could be confusing to someone not familiar with the inner workings of the empty? method. So for most cases B seems like the best option, though there too I would edit the error message to 1) not mention the local variable 's', and 2) maybe not mention that the argument has to respond to 'size'.

###
# 2. Should active record have an after_delete callback? Why?
###

Answer: I don't think so. ActiveRecord callbacks are lifecycle events. AR objects have 3 major lifecycle events Create, Update, and Destroy. Each of those is a series of smaller events (for example, Create calls New to instantiate an object, then Save to persist it etc.). All Delete does is fire off a DELETE SQL call to the database to delete the record, Destroy calls Delete as part of the Destroy lifecycle event, but the Delete method itself isn't a lifecycle method. Just like there is no after_new callback, similarly it wouldn't make sense to have an after_delete callback.

###
# 3. Which implementation is best? Why?
###

# A
module Alertable
  attr_accessor :alert_method
 
  def alert?
    !alert_method.nil?
  end
end

class CalendarEvent
  include Alertable
 
  def start_time
    # ...
  end
 
  def end_time
    # ...
  end
end

# B
class Alert
  attr_accessor :alert_method
 
  def alert?
    !alert_method.nil?
  end
end

class CalendarEvent < Alert
  def start_time
    # ...
  end
 
  def end_time
    # ...
  end
end

# C
class CalendarEvent
  attr_accessor :alert_method
 
  def alert?
    !alert_method.nil?
  end
 
  def start_time
    # ...
  end
 
  def end_time
    # ...
  end
end

Answer: I believe A is the way to go about it.

C. is not a great OO way to go about it, calendar events aren't the only time you would want an alert, so it makes sense to have the Alert logic moved out so it can be reused elsewhere.

It doesn't make sense to have CalendarEvent inherit from an Alert class, calendar events aren't a subclass of alerts (they aren't a "type" of alert), they are events that use alerts, so including an "Alertable" module in CalendarEvent is the implementation that makes most sense.

// JavaScript
//
// 1. What is the significance of, and reason for, wrapping the entire
// content of a JavaScript source file in a function block?
//
(function() {
    // Source code here
})();

Answer: Wrapping the whole file in a function is done to limit the scope of any variables and functions in the file so they 1) can't be accessed from outside the file and b) don't overwrite variables elsewhere that maybe have the same names.

//
// 2. Below is a pure JS version of jQuery's toggleClass()
// function. It takes a DOM element as the first argument and a string
// as the second argument representing a single CSS class
//
// What problems can you identify with this method? How would you write it?
//


function toggleElementClass(element, className) {
    if (element.className.indexOf(className) > -1) {
        element.className = element.className.replace(new RegExp(className, 'g'), '');
    } else {
        element.className += " " + className;
    }
}

Answer: The function looks very "messy". It just seems horrible inefficient to treat a list of classes just as one long string and start regexing through it to find a class and remove it. Additionally, adding a class adds a space before it and removing it doesn't remove that space, so calling this function will leave a very messy class-list full of white-spaces (and calling the function on an element without any classes will produce a class with a space in front of it).

I believe a prettier way to do this would be to split className into an array of classes, individual classes can then be added and/or removed in a much cleaner way following which you can then join them again cleanly, like this:

function toggleElementClass(element, className) {
  var classes = element.className.split(" ");
  var i = classes.indexOf(className);

  if (i > -1) {
      classes.splice(i, 1);
  } else {
      classes.push(className);
  }

  x.className = classes.join(" ");
}
// 3. Which implementation is better? Why?
//

// A
function Clock(hour, minute, second) {
    this.hour = hour;
    this.minute = minute;
    this.second = second;

    this.tick = function() {
        this.second += 1;
        return this;
    };

    this.tock = function() {
        this.second += 1;
        return this;
    };
}

var c = new Clock(10, 10, 0);
c.tick().tock();

// B
function Clock(hour, minute, second) {
    this.hour = hour;
    this.minute = minute;
    this.second = second;
}

Clock.prototype = {
    tick: function() {
        this.second += 1;
        return this;
    },

    tock: function() {
        this.second += 1;
        return this;
    }

}

var c = new Clock(10, 10, 0);
c.tick().tock();

Answer: B. Adding a method to the prototype vs. the constructor has quite a few advantages:

a) If the function needs to be changed it only has to be changed once in the prototype and all the instances will inherit it from there, where if the function is defined in the constructor, changing the function will only affect future instances, any instance already instantiated will still have the older function.

b) Having the function in the constructor means that every instance of the object will have its own copy of the function (not a problem for your Clock, but if Twitter had a function on its User object, replicating it for its 328M users will take significant memory)

c) An aesthetic point I noticed when running your code. tick() and tock() both return 'this'. If the functions get defined on the prototype, the returned 'this' is a clean Clock object (Clock {hour: 10, minute: 10, second: 2}), while if you define the functions in the constructor the returned object includes those functions and has a "dirtier" look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment