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

Need Driven Development: Tools from Chef Server Development

Need Driven Development: Tools from Chef Server Development

Do you care about reproducible builds? Does your application manipulate JSON or interact with a SQL-based database? This talk will present three open source libraries developed to support the Erlang-powered Chef Server.

We’ll cover a rebar plugin for locking all project dependencies, a tool for accessing and validating JSON, and a library for interacting with an RDBMS with a unique "No ORM” approach.

concrete
ej
sqerl
rebar_lock_deps_plugin

Seth Falcon

May 17, 2014
Tweet

More Decks by Seth Falcon

Other Decks in Programming

Transcript

  1. concrete 1. project generator with standard make targets 2. edoc

    to markdown included 3. dev-only dependencies 4. fancy dialyzer goodness 5. relx support
  2. $ concrete init todo Creating the todo project with concrete

    Would you like an active application? (y/n): y Now try: cd todo; make
  3. $ cd todo $ ls -1 Makefile README.md concrete.mk include/

    priv/ rebar.config rebar.config.script src/ test/
  4. %% @author Seth Falcon <[email protected]> %% @copyright Copyright 2011-2012 Seth

    Falcon %% %% @doc Tools for working with Erlang terms representing JSON. %% %% The ej module is intended to make it easy to work with the Erlang %% structure used by `mochijson2' to represent JSON. You can use %% `ej:get' to walk an object and return a particular value, or %% `ej:set' to update a value. %% %% @end -module(ej).
  5. %% -- rebar.config excerpt -- {dev_only_deps, [ {proper, ".*", {git,

    "git://github.com/manopapad/proper.git", "master"}} ]}.
  6. ▸ Creates a base ~/.dializer_plt if needed ▸ deps.plt just

    for your deps ▸ make dialyzer like it says on the tin
  7. ej

  8. JSON { "type" : "todo", "title" : "Tie shoes", "priority"

    : 1, "meta" : { "created_at" : "2014-05-04 02:59", "created_by" : "seth" } }
  9. LIFE BEFORE EJ Obj = {[{<<"type">>, <<"todo">>}, {<<"title">>, <<"Ties shoes">>},

    {<<"priority">>, 1}, {<<"meta">>, {[{<<"created_at">>: <<"2014-05-04 02:59">>}, {<<"created_by">>, <<"seth">>}]}} ]}
  10. LIFE BEFORE EJ {L1} = Obj, {L2} = proplists:get_value(<<"meta">>, L1),

    CreatedBy = proplists:get_value(<<"created_by">>, L2).
  11. LIFE BEFORE EJ {L1} = Obj, {L2} = proplists:get_value(<<"meta">>, L1),

    CreatedBy = proplists:get_value(<<"created_by">>, L2).
  12. A BRIGHTER TOMORROW WITH EJ CreatedBy = ej:get(["meta", "created_by"], Obj),

    Obj2 = ej:set(["meta", "created_by"], Obj, <<"Ezra">>)
  13. EJ IS HERE TO HELP Spec = {[{<<"type">>, <<"todo">>}, {<<"title">>,

    string}, {opt, {<<"description">>, string}}, {opt, {<<"priority">>, integer}}, {<<"meta">>, {[{<<"created_at">>: string}, {<<"created_by">>, string}]}} ]}, ej:valid(Spec, Obj)
  14. ej:valid/2 ▸ Exact match ▸ Type ▸ String match (regex)

    ▸ array map ▸ object map ▸ fun match
  15. -record(todo_item, { id :: integer() , title :: binary() ,

    description :: binary() , priority :: binary() , created_at :: binary() , created_by :: binary() }).
  16. AN ITEM Item0 = #todo_item{title = <<"write tests">>, priority =

    <<"hot">>, description = <<"use eunit">>, created_by = <<"me">>}
  17. INSERT, UPDATE, FETCH [Item1] = sqerl_rec:insert(Item0). UItem0 = Item1#todo_item{priority =

    cool}. [UItem1] = sqerl_rec:update(UItem0). [FItem] = [UItem1] = sqerl_rec:fetch(todo_item, title, <<"write tests">>).
  18. 7?!

  19. SCHEMA CREATE DOMAIN todo_time AS TIMESTAMP WITH TIME ZONE DEFAULT

    NOW() NOT NULL; CREATE TYPE priority_enum AS ENUM ('cool', 'warm', 'hot', 'burning');
  20. SCHEMA CREATE TABLE todo_items ( id BIGSERIAL PRIMARY KEY, title

    TEXT NOT NULL UNIQUE, priority priority_enum NOT NULL DEFAULT 'warm', description TEXT, created_at todo_time, created_by TEXT NOT NULL );
  21. USE EXPRECS AND GET THESE FOR FREE -callback '#get-'(atom(), db_rec())

    -> any(). -callback '#new-'(atom()) -> db_rec(). -callback '#fromlist-'([{atom(), _}], db_rec()) -> db_rec(). -callback '#info-'(atom()) -> [atom()].
  22. YOU'LL NEED TO WRITE THESE 3 -callback '#insert_fields'() -> [atom()].

    -callback '#update_fields'() -> [atom()]. -callback '#statements'() -> [default | {atom_list(), iolist()}].
  23. -record(todo_item, { id :: integer() , title :: binary() ,

    description :: binary() , priority :: binary() , created_at :: binary() , created_by :: binary() }).
  24. sqerl_rec:statements([todo_item]) [ ] todo_item_fetch_all [ ] todo_item_fetch_by_title [ ] todo_item_fetch_page

    [D] todo_item_insert [D] todo_item_update [D] todo_item_delete_by_id [D] todo_item_fetch_by_id
  25. sqerl_rec:statements([todo_item]) {todo_item_fetch_by_title, "SELECT id, title, [...] FROM todo_items WHERE title

    = $1"}, {todo_item_insert, "INSERT INTO todo_items(title, description, priority, created_by) " "VALUES ($1, $2, $3, $4) RETURNING [...]"}, {todo_item_update, "UPDATE todo_items SET title = $1, description = $2, " "priority = $3 WHERE id = $4 RETURNING [...]"},
  26. WARTS ▸ no connection control, no transaction support ▸ timestamp

    handling doesn't include TZ ▸ hard-coded pool name in pooler ▸ some no longer needed indirection since just pg ▸ using an old-ish fork of epgsql
  27. NOPE ▸ can't trust 3rd parties. ▸ your dep might

    be tagged but what about it's deps? ▸ makes extra work at release time for code you own.
  28. ?!

  29. New deps: lager, goldrush Removed deps: fast_log Updated deps: chef_db

    2014-02-06 a1b69c1 Merge pull request #50 from opscode/of/solr4 2014-02-06 d69d5ff Move chefp to chef_db chef_index 2014-02-21 6f44357 Merge pull request #15 from opscode/sf/solr4 2014-01-03 549054b Move chef_index_expand to chef_reindex