Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rails - Still the Best Framework for Bootstrapping

Rails - Still the Best Framework for Bootstrapping

This year we launched a new product in 6 weeks - from initial commit to accepting customers. We could have used a number of languages to build KBSimple, but we chose Rails to bootstrap it. The reason is simple: Rails is still the best framework for bootstrapping new web applications.

In this talk I'll go through the 6 week evolution of the product, talk about the various gems and techniques that were essential in reducing the amount of time it took to launch, and talk about some of the challenges we faced along the way.

Anthony Eden

October 04, 2013
Tweet

More Decks by Anthony Eden

Other Decks in Programming

Transcript

  1. 2005 Sunday, October 6, 13 Java frameworks became unwieldy Came

    full circle with Servlets and JSP Simplify
  2. 2006 http://www.flickr.com/photos/30784280@N05/4338666833 Sunday, October 6, 13 First RailsConf Feels all

    brand new Rails development cuts time to market significantly Testing is baked in This framework is opinionated Antidote to the complexity of Java
  3. 2013 http://www.flickr.com/photos/9491236@N03/2844346957 Sunday, October 6, 13 Time to market is

    even better thanks to gems and established techniques This framework is still opinionated Antidote to the problem of too many choices and over engineering
  4. /* Zone and record representations */ type ZoneNotification struct {

    Name string `json:"name"` " Sha string `json:"sha"` " Url string `json:"url"` " Action string `json:"action"` } Sunday, October 6, 13
  5. type hub struct { broadcast chan string " connections map[*connection]bool

    " register chan *connection " unregister chan *connection } Sunday, October 6, 13
  6. var h = hub{ " broadcast: make(chan string), " connections:

    make(map[*connection]bool), " register: make(chan *connection), " unregister: make(chan *connection), } Sunday, October 6, 13
  7. func (h *hub) run() { for { select { case

    c := <-h.register: h.connections[c] = true case c := <-h.unregister: delete(h.connections, c) close(c.send) case m := <-h.broadcast: for c := range h.connections { select { case c.send <- m: default: delete(h.connections, c) close(c.send) go c.ws.Close() } } } } } Sunday, October 6, 13
  8. -module(erldns_packet_cache). -behavior(gen_server). % API -export([start_link/0, get/1, put/2, sweep/0, clear/0]). %

    Gen server hooks -export([init/1, handle_call/3, " handle_cast/2, " handle_info/2, " terminate/2, " code_change/3 ]). -define(SERVER, ?MODULE). -define(SWEEP_INTERVAL, 1000 * 60 * 10). % Every 10 minutes -record(state, {ttl, tref}). Sunday, October 6, 13
  9. %% Public API start_link() -> gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).

    get(Question) -> gen_server:call(?SERVER, {get_packet, Question}). put(Question, Response) -> gen_server:call(?SERVER, {set_packet, [Question, Response]}). sweep() -> gen_server:cast(?SERVER, {sweep, []}). clear() -> gen_server:cast(?SERVER, {clear}). Sunday, October 6, 13
  10. init([]) -> init([20]); init([TTL]) -> ets:new(packet_cache, [set, named_table]), {ok, Tref}

    = timer:apply_interval(?SWEEP_INTERVAL, ?MODULE, sweep, []), {ok, #state{ttl = TTL, tref = Tref}}. Sunday, October 6, 13
  11. handle_call({get_packet, Question}, _From, State) -> case ets:lookup(packet_cache, Question) of [{Question,

    {Response, ExpiresAt}}] -> {_,T,_} = erlang:now(), case T > ExpiresAt of true -> lager:debug("Cache hit but expired"), {reply, {error, cache_expired}, State}; false -> lager:debug("Time is ~p. Packet hit expires at ~p.", [T, ExpiresAt]), {reply, {ok, Response}, State} end; _ -> {reply, {error, cache_miss}, State} end; Sunday, October 6, 13
  12. handle_call({set_packet, [Question, Response]}, _From, State) -> {_,T,_} = erlang:now(), ets:insert(packet_cache,

    {Question, {Response, T + State#state.ttl}}), {reply, ok, State}. Sunday, October 6, 13
  13. handle_cast({sweep, []}, State) -> lager:debug("Sweeping packet cache"), {_, T, _}

    = erlang:now(), Keys = ets:select(packet_cache, [ {{'$1', {'_', '$2'}}, [{'<', '$2', T - 10}], ['$1']} ]), lager:debug("Found keys: ~p", [Keys]), lists:foreach(fun(K) -> ets:delete(packet_cache, K) end, Keys), {noreply, State}; handle_cast({clear}, State) -> ets:delete_all_objects(packet_cache), {noreply, State}. Sunday, October 6, 13
  14. (ns cbe.functions (:use [clojure.test])) ;Anonymous function (let [f (fn [x]

    (+ x 1))] (is (= 3 (f 2)))) ;Define a function (def add-fn (fn [a b] (+ a b))) (is (= 3 (add-fn 1 2))) ;Define a function with defn macro (defn add-defn [a b] (+ a b)) (is (= 3 (add-defn 1 2))) Sunday, October 6, 13
  15. (ns cbe.functions (:use [clojure.test])) ;Anonymous function (let [f (fn [x]

    (+ x 1))] (is (= 3 (f 2)))) ;Define a function (def add-fn (fn [a b] (+ a b))) (is (= 3 (add-fn 1 2))) ;Define a function with defn macro (defn add-defn [a b] (+ a b)) (is (= 3 (add-defn 1 2))) JUST KIDDING! Sunday, October 6, 13