Geeks, Not Ninjas
eBay Israel Innovation Center’s Blog
  • Farewell to ISC’s Rock Star Ninja Coders

    rachel April 13, 2013

    Two years ago when I took the job as the Office Manager at The Gifts Projects (TGP), I must admit – I was hesitant. I didn’t want to be doing something administrative, but I knew it was a foot in the door to the exciting world of startups, which like every other good Israeli my age, I was dying to be a part of. So, when I was offered the job, I decided to dive in head first and give it a try. After all – what did I have to lose?

    I of course never let my hesitation on, because they were hesitant too. I was over qualified and during the interview Ron (my boss) basically told me that he knows my type – I’ll get bored after a few months and leave – he gave me two years at most. And he was right, I am the type to get bored, but I promised I was there for the journey and that he should take a chance on me. It was one of those sliding door moments for me, because if he wouldn’t have offered me the job I was going to head off to Southeast Asia to travel or look for a place to volunteer in Africa. Self-fulfilling or just spot on, his prophecy came true and I finished working at the ISC after two years (and a month to the date). I am thankful every single day that they took a chance on me because the experience of working with Ron, Erez, Matan, Maya, Ziv, Miki, Yon, Danni, Gartner, Adam, Itay, Ido, Shay, Ariel, Guy and Marty was absolutely priceless.

    On my first day of work, Ron had a long list waiting for me to do of odds and ends that he hadn’t gotten around to. He thought it would take a few months, but after about 6 weeks I finished everything and came to him and asked him for more projects and to start working full time (I was originally hired to work 9 AM- 3 PM). And that basically describes my two years at TGP/ISC. The more I got involved in the ins and outs of the company, the more projects and work I wanted. I discovered that being an office manager at a startup is about being an entrepreneur and the bigger you dream the more opportunities you have.

     

     

     

    I could have easily spent two years working 9-3 and focused on the administrative aspects of the job, but I made a choice to look beyond the job description and with the support and encouragement of my boss I turned my job into a multidisciplinary and far reaching position with a lot of responsibility and variety. Removing overhead from founders in and of itself is a huge contribution at a startup, as it allows them to focus on the core activities of the company and that should not be taken lightly. But focusing on administrative work wasn’t enough for me. The team’s love and dedication to their work was inspiring and I wanted in on the action (to those who know me, shocking, eh?). I wanted to understand what product meant and why things worked the way they did, how the business was run and basically how I could get my hands on what everyone else in the company was doing. Yes, even at the age of 28, I looked at the other kids on the play ground and wanted what they had, but how could I help myself? When spend the majority of your day with 7 people in an 80 square meter office space and they live, breath, and eat (well talk about when they eat) coding the most aesthetically appealing lean mean Group Gifting experience the internet had ever seen, you have to be crazy not to want to be a part of it.

    And with a little bit of encouragement and an open minded boss I turned my position into an internship program for sales, marketing, product and programming. I thought I knew a bit about technology and social media when I started, but I discovered that I was borderline technophobe and an extremely conservative user. I would ask for every tweet that I wrote for TGP to be approved and couldn’t figure out why people would want to connect to Facebook to use an online service or even what that meant. The only item I had ever bought on eBay was a pair of UGG boots (which I still proudly wear by the way) in 2006.

    At first Matan, our Head of Product would show me a new experience that they put together and ask me what I think and to give feedback regarding how intuitive the experience was and any content input I had. Then I started to write the content and at a certain stage due to sheer need for addition man power and upcoming deadlines, it became more cost effective for Erez, our CTO to teach me how to write the content directly in YAML files. So I got a GitHub profile and learned what it meant to push and pull code into staging and production. To someone who studied computer science or has coded their whole life it may seem trivial, but it was a huge deal – especially since I pushed broken code and knocked down the system right before important phone calls with clients once or twice – but hey, you learn way more from the mistakes you make and not by getting things right all the time.

    In April last year, we revamped the eBay Group Gifts payment method. And guess who got the chance to define this from A-Z? One of the best parts about working with the programmers at ISC (or now IIC) is that they care about product almost as much as coding. Now I haven’t worked with other programmers, so I only hear rumors, but I understand that this should not be taken for granted. Planning this feature took up every free moment for several weeks – I totally neglected the refrigerator (that is when you know I was really busy – when I let the yogurt stock run out), but 2 sprints later, just in time for Mother’s Day, we rolled out a new and improved eBay Group Gifts utilizing PayPal’s pre-approval API.

    Leaving the ISC to pursue my dream of living and working in Africa was not easy. I left behind people that were more than just co-workers. Clichés aside, they really were like my family. I don’t think there was ever a day in the two years that I worked there that dreaded going to work – quite the opposite. I loved coming to our secret hideaway above Rothschild’s Kitchen everyday and I loved even more coming to our dream offices on Rothschild 13. Even on the most frustrating and annoying days at work (and there were many), I loved being there. I learned something new every day and I was constantly inspired to learn more, try new technologies, encouraged to ask questions and they even tolerated me nudging the hell out of them so I could better understand what we did and why we did it.

     

     

    I am certainly no guru, but I leave feeling comfortable with technology, have a huge appreciation for good user experience and aesthetically pleasing websites/applications, understand how challenging building a good product can be, but how satisfying it is when you get there, and most importantly recognize how important it is to be knowledgeable about technology and learn how to code (and no I still don’t know how to, but it is on my backlog of things I must do, just like moving to Africa). I will take with me for the rest of my career the things I learned about technology, cultivating creativity, how to build a successful startup, people management, project management, entrepreneurship, innovation, and friendship — and the best farewell video ever made.

     

     

    Thank you for the opportunity to work with you – for the knowledge you shared and for opening my eyes up to the world of technology.

  • Gemifying our way to future projects

    Itay January 20, 2013

    After working on several new products at the ISC for the past year, one of the things that always bugged us as a team is the amount of copy & paste we had to do from one project to the other to the libs that we wrote. These libs could apply to any project, but we just didn’t take the extra steps to make them self-contained. As the amount of products that we work on increases, it makes a lot of sense for us to extract these components into ruby gems that can be shared across our projects. This gives us quite a few benefits, such as:

    • No more copying & pasting lib code! Just add the desired gems to the project’s Gemfile and voila!
    • A lot easier to maintain these libs now that it’s separate from our project. No more different versions of the same code in different projects, trying to figure out which one is the most up-to-date.
    • These libraries are all open-sourced by us, so if anyone else finds them useful and contributes to them, everyone benefits!

    So without further ado, here they are, in no particular order:

    gem 'batlog'

    Link to GitHub repository

    BatLog is our little logging helper. It allows you to log into more than just the default RailsLogger which saves the logs into text files. You can add a DbLog that, as the name suggests, adds your logs into your DB, and also an ExceptionalLogger that notifies exceptional.io of critical errors that occurred in your system with more details. You can write your own custom logger that can report to other external services. It’s also possible to provide BatLog with a log context that can provide additional data on a log entry, such as request data, user state, etc. One last thing – if BatLog fails to log in any logger, it notifies the other loggers about it.

    gem 'configreader'

    Link to Github repository

    A common pattern that is used in rails apps is to load up static configuration files into simple hash objects, that can then be used across our Rails app from any object. This is achieved by defining for each static configuration an initializer file that loads up the data into a const on Object. Most of the time, these configuration files contain configurations that are environment-specific, and other times these are just flat configurations.

    In one of our projects, we needed another layer of awareness. We then thought that this can be done a bit nicer. ConfigReader offers to load up your configuration files into a container object that gives you access to your data with methods, instead of hash keys. So when you have a configuration file with different settings for each environment, let’s say Facebook, instead of accessing your data like so:

    FACEBOOK[Rails.env]["app_id"]

    With EnvConfigReader you can access it like so:

    FACEBOOK.app_id

    Another great feature of ConfigReader that I love is that you can automatically create these configuration files by following a simple directory convention, and a little initializer with a configuration setting. (No more initializer files for configuration files, yay!)

    gem 'creators'

    Link to GitHub respository

    In one of our latest projects, we saw a pattern in our controllers that is worth extracting into its own Concern. The pattern is model creation and updating. ActiveRecord gives you great tools to handle it easily, but when the size of your forms increases, there’s a need to slice up the request params, and prepare them in a certain way for the model. You may also want to add custom validations that are not so relevant to the model in question. You can read more about Creators in Yon’s post, ‘Trimming the fat from your controllers’.

    gem 'isc_analytics'

    Link to GitHub repository

    This gem has really helped us clean up a lot of boilerplate Analytics code that is required to setup KISSmetrics and Google Analytics. It’s more of a wrapper for KISSmetrics, since that’s our primary Web Analytics tool, but it can be easily extended to other tools.

    gem 'iscjs'

    Link to GitHub repository

    A rails engine that includes all of the jQuery plugins we wrote at the ISC. Again, this is another great way to share libraries across different projects.

    gem 'controller_support'

    Link to GitHub repository

    This gem is a helper for a convention we’re using to manage Rails Controllers. Also mentioned here.

    If you want to start gemifying your libraries, I recommend reading this post from Pivotal Labs about working on gems locally from within your project. IMHO its a great way to migrate your libraries into a gem.

  • Trimming the fat from your controllers

    Yon December 3, 2012

    I gave a talk at the Rails-Israel conference on how we work to trim down our controllers.

    Today I’d like to take an in-depth look and explain why and how we do that.

    You can view the slide deck here (link).

    Why do we want to trim our controllers?

    Controllers are a basic and integral part of any Rails app that you build, every interaction a user has with your system passes through one.

    A controller has many responsibilities, we can try and refine the basic responsibilities as:

    • Retrieves the data from the incoming request
    • Deciding on and writing the response
    • Saving any data needed

    But a controller is usually also where you handle – Authentication, Authorization, Manipulate Data, Presentation Logic, Redirecting and lots of other stuff not core controller business.

    I’d like to go over several methods that we use to combat bloaty controllers.

    Queries and Scopes

    Queries are a piece of model logic that easily leaks into controllers.

    Intimate knowledge of the models appears in the controller.

    This usually happens when you want to display a subset of objects in a view.

    class ItemsController < ApplicationController
     def show
        @items = Item.where(:type => 2).limit(100)
        respond_with(@items)
     end
    end

    So we start by moving the query logic from the controller into where it belongs – the model.

    We can use scopes a feature that exists for quite some time in Rails to move the knowledge on how to query a specific set of objects into the model. Essentially we’re exposing the what and hiding the how.

    class Item < ActiveRecord::Base
        scope :expensive_items, where(:type => 2)
        scope :latest, limit(100)
    end
    class ItemsController < ApplicationController
     
     def show
        @items = Item.expensive_items.latest
        respond_with(@items)
     end
     
    end

    Observers and Callbacks

    Another thing to look out for is model logic and callback behavior making its way into your controller code.

    A lot of times you’ll write CRUD code (code that supposedly just creates a model) and then does something else once it happens.

    Things like sending out emails, push notifications or any other notification-like behaviors.

    class ItemsController < ApplicationController
     def create
        @item = Item.create(params[:item])
        if @item
            ItemMailer.deliver(@item) # this line
            redirect_to item_path(@item)
        else
        …
       end
     end
    end

    These types of behaiviours should not be a part of the controller, they add nothing to the control flow.

    They are a by-product of creating a new model.

    That’s why when faced with these types of issues we extract them into Observers

    Observers are a good way to separate event based behaiviours into separate classes.

    For example we can extract the email code into it’s own observer.

    Every time a new item is created a new email is sent.

    class ItemMailObserver < ActiveRecord::Observer
      observe :item
     
      def after_create(item)
        ItemMailer.deliver(item)
      end
    end

    You can read more about observers here http://guides.rubyonrails.org/active_record_validations_callbacks.html#observers

    Creating and Updating Models

    Another source of fat controllers is the code that actually creates the model.

    Rails has a awesome set of defaults for creating models out of form and request data.

    And that’s what you’ll see in tutorials or very simple stuff.

    class ItemsController < ApplicationController
     
      def create
        @item = Item.create(params[:item])
      end
     
    end

    But from our experience this is where the controller grows fastest, after months of coding it’s not unusual to find your method looking like this.

    class ItemsController < ApplicationController
     
      def create
        item_params = params[:item].slice(…)
        item_params[:category_attributes] = params[:category]
        @item = Item.build(item_params)
        @item.owner = current_user
        @item.save
        ...
      end
     
    end

    The process of actually building a model usually includes these things:

    • Slicing and merging the params hash to make it fit the Rails model
    • Link the newely created model to existing models in the system
    • Custom validations of the params received from the user
    • Complex logic deciding when to create new sub-models and when to link

    We extracted all of this into a new Object in the Rails system that we call Creators.

    A Creator is an Object that receives the raw parameters hash and any other attributes it might need, runs all the custom logic and params slicing and uses Rails’ defaults to create the model.

    Here’s an example for an item creator that does the same things we did in the example at the top

    class ItemCreator < Creators::Base
     
      def refine_params
        @params[:item].slice(…)
                       .merge(:category_attributes => @params[:category])
      end
     
      def after_build
        @item.owner = current_user
      end
     
    end

    The usage is very simple

    class ItemsController < ApplicationController
     
      def create
        creator = ItemCreator.new(params, current_user)
        if creator.save
          redirect_to item_path(creator.item)
        else
          logging.error "Errors creating item", creator.errors()
        ...
      end
     
    end

    This way we have a class ItemCreator who’s single responsibility is to convert the users request into whatever is needed to create the new model. It’s easier to test because we separated responsibilities, we can easily mock out the creation itself in the controller flow. And we still build on all the default behavior and expectations of Rails to actually create the new model.

    In the conference I introduced this concept as a WIP that we started looking at not long ago.

    Becuase of all the warm feedback we got from the people there we decided to go ahead and extract it to a gem.

    You can check out the code on GitHub or just add the gem to your GemFile now

    gem 'creators'

    Nested Resources and More Controllers

    A quick win in the fight for thin controllers is really simple – create more of them.

    It’s stupidly easy to add a new action into an already existing controller, but that’s not always the right place to put it.

    class ItemsController < ApplicationController
        def create_category
            …
        end
    end
    resource :items do
     
     member do
       post :create_category => "items#create_category"
     end
     
    end

    We found ourselves doing things like this a bit too much, creating sub-models from an already existing controller but actually hiding true CRUD functions. You can see it from the name of the action, and from the routes definition.

    Rails is really good for handling CRUD actions and resources, so a very good solution in this case is to extract those methods into their own nested controllers.

    class CategoryController < ApplicationController
        def create
            …
        end
    end
    resource :items do
     resource :category
    end

    After we do these extractions we have no reference to the creation of categories from the items controller. We have a new controller who is now responsibile to handle categories in an item.

    This extraction is one of the easier to do, but it raises a new issue. We need to share behavior and functionality between these two controllers, in this case they both need to be able to load the current resource.

    Sharing behavior – Mixins and Controller Concerns

    A controller has a lot of behavior and functionality that isn’t specific only to itself.

    Things that we need to share between two or more controllers, things like Authorization, Authentication, Error handling & Resource loading.

    There are several different ways to share these behaviors.

    The first is to move these methods up to the ApplicationController, the base controller that everyone inherits from.

    This is a good solution for application-wide behaviors (things like Authentication and Error handling),

    but isn’t a good solution when we’re talking about controller-specific behaviors (things like resource loading) which you might need to share between several controllers but not all of them.

    The solution that we really like for sharing behavior between several controllers is – Mixins.

    Ruby mixins are a cool standard way to extract behavior code into a separate entity and add it (mix it in) to whatever object you need.

    module ItemSupport
     
      def current_item
        Item.find(params[:item_id] || params[:id])
      end
     
    end

    This lets us declare a module that can mixin the resource loading behiavour for an item, we can then easily include it into whatever controller we need.

    class ItemController < ApplicationController
        include ItemSupport
    end

    We can also include it into non controller objects – making test easier as we can test everything in complete isolation. We can also add these supports into different kinds of objects – for example we have a LocalizationSupport which we include into our mailers thus sharing the behavior of localization between controllers and mailers.

    We extend the basic usage of ruby mixins with ActiveSupport::Concern in a convention that we call ControllerSupports.

    ControllerSupports is just a convention of using ActiveSupport::Concern to write better mixins – in an easier way.

    It gives us the option to declare dependencies betweeen mixins (keeping our code DRY) and enables us to declare class method functionality like before_filters and helper_methods inside the mixin instead of having to duplicate it next to every inclusion.

    Here’s an example for a Item ControllerSupport which depends on the UserSupport and defines the current item as a helper method.

    module ItemSupport
     
      extend ActiveSupport:Concern
     
      include UserSupport
     
      included do
          helper_method :current_item
      end
     
      def current_item
          current_user.items.find(params[:item_id] || params[:id])
      end
     
    end

    We love this method of extracting functionality, it lets us easily share behavior, it’s easier to test and it makes it clearer when and where to add new methods.

    Serializers and Presenters

    One last topic I want to talk about is something that I didn’t have time to get to in my talk and that’s – presentation logic and serializers.

    Our latest application was our first experience with a real client-side application, the first time we used Backbone in the real world.

    When you write a client-side application serialzing models into JSON becomes something that you do a lot, and usually you find yourself doing it in your controllers.

    Serializing models can become a very complex thing especially when you need to serialize nested models or consider the scope of the application (who’s requesting this data).

    The trivial solution is to override the models as_json and have the slicing and merging logic there.

    class Item < ActiveRecord::Base
        def as_json(options = {})
            data = super(:only => [:id, :name])
            data.merge!(:category => category.name)
            data
        end
    end

    The problem with this method is that you have specific controller serialization logic inside a model, you won’t be able to serialize different data based on the controller action. Say you want to display different data for the index action and the show action – it’s a lot harder to do when the code is in the model.

    The other thing is that you can’t access the context of the controller from the as_json function. Lets say you want to serialize more information if the item belongs to the current_user or hide pieces of information if you’re a crawler.

    That’s why we recommend using ActiveModel::Serializer a cool gem that encapsulates the serialization of ActiveModel objects into a separate object.

    This enables you to customize the scope of your serialization, easily serialize nested models and arrays of models and enables you to maintain separate serializers for different parts of your application.

    Summary

    So I wanted to share with you these different methods and tricks we use to try and keep our controllers in check.

    It’s a never-ending battle, every feature you add, every bug you fix, you’ll probably need to touch the code in the controllers – so be conscious about what you do.

    We feel that extracting behavior into encapsulated single responsibility objects is one of the best ways to not overload controllers, it helps us keep our apps maintainable and make everything easier to test.

    Do you have things that you do to keep your code small? Share it with us in the comments.

  • Testing in the ISC

    ifeins November 11, 2012

    In this series we will talk about the tools we use for testing our products.
    This post will be technical in nature and will focus on our testing stack.

    On the server side spectrum we use Ruby on Rails, and on the client side we develop in Coffeescript, SASS, HTML 5, Backbone.js and many other client side libraries.
    This post focuses on our server side testing, however we also do client-side testing using frameworks such as Jasmine and Selenium but this will have to wait to a later post :)

    Case study

    Before we dive into code examples we will present a feature we worked on to demonstrate some of the features of the testing frameworks we thought worth sharing.

    eBay Group Gifts is a platform for creating gifts and splitting their cost by inviting friends via Facebook or email to chip in.

    When the gift organizer creates a campaign (the term used in the code for the entity that encapsulates the gift, the participants and their payments) he/she adds the participants he/she wants to invite. The organizer can always add, replace or remove invitees from the campaign and change the requested amount.

    This feature named “Edit invitees” includes a frontend (see screenshot below) where the organizer can edit the list of invitees and a backend which receives all the parameters sent from the form, compares them to the participants’ details currently in the database and update the participants’ details accordingly.

    Test stack

    RSpec

    Ruby on Rails comes bundled with the test-unit framework which is similar to frameworks such as JUnit in the Java world.
    However in the ISC we prefer to use RSpec as it allows us to describe the behaviors we expect from our code in a more fluent manner.
    With RSpec both the tests (also known as specs) and the output they produce are much more readable.

    To demonstrate some of RSpec capabilities we will use the “Edit invitees” feature we described above.
    In this feature the component responsible for applying the delta between the participants’ details in the database and the participants’ details from the “edit invitees” form is called ParticipantUpdater or simply PU.
    In the scope of the feature we will talk here about three kinds of participants:

    • Organizer – the campaign organizer.
    • Invitee – a participant that was invited to chip in for the group gift.
    • Contributor – an invitee that has already chipped in for the gift.

    For each participant type there is a set of limitations:

    • The organizer cannot be removed from the campaign.
    • A contributor cannot be removed from the campaign, nor can the suggested amount be changed (since he already paid).
    • The suggested amount of all types of participants cannot exceed the gift’s total price.

    While there are client side validations on all those limitations we still need to enforce them in the server-side code.
    One possible way to test those limitations in the PU is like so:

    describe ParticipantUpdater
      let(:contributor) { } # create contributor logic
     
      describe "Organizer" do
        it "cannot be assigned a suggested amount higher than gift’s price"
        it "cannot be removed from the campaign"
      end
     
      describe "Invitee" do
        it "cannot be assigned a suggested amount higher than gift’s price"
      end
     
      describe "Contributor" do
        it "cannot be assigned a suggested amount higher than gift’s price"
        it "cannot be removed from the campaign"
        it "suggested amount cannot be changed"
      end
     
    end

    We omitted the body of the it clauses and as you can see there are a lot of duplicate tests between the 3 kinds of participants.
    One solution is to extract the assertions inside those it clauses into helper methods, but that still leaves us with the it clauses themselves.

    This is where RSpec’s shared examples feature comes in handy.
    It allows to group a certain set of expected behaviors (it clauses) and then reuse them in other tests.

    For example let’s take the “cannot be assigned a suggested amount higher…” limitation. This limitation is relevant to all participants.
    Using the shared examples feature we can re-write the following code like so:

    shared_examples :any_participant do
      it “cannot be assigned a suggested amount higher than gift’s price” do
        test logic...
      end
    end

    Then when we describe the organizer we can use it as follows:

    describe “Organizer” do
      it_behaves_like :any_participant
      other organizer-specific tests…
    end

    As you can see the it_behaves_like method instructs RSpec to include to the any_participant shared specs.

    Let’s zoom in on the contributor specs:

      describe "Contributor" do
        it "suggested amount cannot be changed" do
          expect {
            # call the method that update the participants details, among them
            # the contributor’s suggested amount
          }.should_not change(contributor, :suggested_amount)
        end
      end

    In the above spec we want to verify that if the user tries to change the suggested amount of a a contributor then the suggested amount remains the same.

    We use the change matcher to do so.
    This matcher inspects the property given to it before and after the code in the expect block runs and returns true if the property changed.
    Since we’re using it in conjunction with the should_not method then the whole test passes if the suggested_amount did not change.
    This is a very expressive way to specify the behavior you expect from your code.

    One last implementation detail that remains to be explained is the let clause at the top of the spec. The let method declares a memoized variable that is initialized when it is accessed.
    This means that the only time the “create contributor logic” is invoked is in the “Contributor” tests. In addition to initializing variables only when necessary this also improves the readability of the spec by listing the entities involved, each with its own declaring block.

    If you’re interested in RSpec, we highly suggest you check out The RSpec Book.

    FactoryGirl-Rails

    FactoryGirl-Rails is an advanced fixtures library for Rails.
    In several of our tests we need to create models and exercise certain actions on them.
    Instead of directly using ActiveRecord to create our models (which will result in a lot of boilerplate code) we use FactoryGirl’s neat DSL to define factories in a single file (usually named factories.rb) and reuse them whenever needed.

    Let’s take a quick look at a sample factories.rb file:

    FactoryGirl.define do
      factory :user do
        ebay_id “user-ebay-id”
      end
     
      factory :participant do
        name “Username”
        email “user@somewhere.com”
        association :user
      end
     
      factory :contributor, :parent => participant do
        role ‘contributor’
      end
    end

    Here we defined factories for two models, the User and the Participant models.
    A user represents a unique eBay user and a participant represents an “instance” of the user in a specific campaign.

    Starting with the basics: how do we create a participant via the factory?
    Simply by placing the following line in the spec initialization code:

    FactoryGirl.create(:participant)

    Another nice feature is that we are not bound to the properties assigned in the factory definition but can pass custom properties to the factory.
    For example if we want to create a participant with a facebook ID, we can simply do so by calling:

    FactoryGirl.create(:participant, :facebook_id => 1234)

    FactoryGirl DSL provides a very easy way to declare the relations between factories.
    In our example – each participant is associated with a certain eBay user.
    In order to describe this we simply specify “association :user” in the participant factory.
    Now each time we create a participant via the factory, it will create its associated user by invoking the :user factory.

    You can also define inheritance between factories.
    As you can see in the example a “contributor” is simply a participant whose role is set to ‘contributor’. It inherits all the properties of a regular participant.

    VCR

    VCR is a nifty little gem that allows you to record responses from web services and replay them in the tests, which greatly reduces the time it takes to run the tests. In several cases, we write integration tests which interact with external APIs.

    These tests are useful both to initially experiment with how these APIs work and later to make sure the code is working as expected once it gets the response.
    Once we have finalized our code, we use VCR to record the responses (which stores them in cassette files) and replay them in our tests.

    The truly amazing thing about VCR is that in your specs you don’t have to mock or stub anything as VCR hooks into the HTTP client libraries you use (HTTPClient, Faraday, Net::Http, etc.)

    The following example is derived from an actual spec we have in one of our products.
    The spec tests an API that receives a user ID and an item ID and checks if the user has placed any orders on this item.

    require 'spec_helper'
     
    VCR.configure do |config|
      config.cassette_library_dir = "spec/vcr_cassettes/some_api"
      config.hook_into :webmock
    end
     
    describe SomeAPI do
     
      API_PARAMS = {
          :multiple_orders => %w(userid1 itemid1),
          :single_order => %w(userid2 itemid2),
          :no_order => %w(userid3 itemid3),
      }
     
      describe :get_orders do
     
        context :api_call_succeeded do
     
          it "should return nil if order details are not present" do
            VCR.use_cassette "no_order" do
              subject.get_orders(*API_PARAMS[:no_order]).should be_nil
            end
          end
     
          it "should return a 1-size array if only one order exist" do
            VCR.use_cassette "single_order" do
              orders = subject.get_orders(*API_PARAMS[:single_order])
              orders.should have(1).order
              orders.should be_all {|order| order.is_a?(SomeAPI::Order)}
            end
          end
     
          it "should return all orders if multiple orders are present" do
            VCR.use_cassette "multiple_orders" do
              orders = subject.get_orders(*API_PARAMS[:multiple_orders])
              orders.should have(2).orders
              orders.should be_all {|order| order.is_a?(SomeAPI::Order)}
            end
          end
     
        end
     
      end
    end

    To instruct your spec to work with VCR you need only do two things:

    • Configure the folder in which the cassette files for this spec are located (see the VCR.configure block at the top).
    • Wrap the invocation of your test subject with VCR.use_cassette block. This instructs VCR to replay the given cassette when an attempt is made to perform a web request.

    Wait! What if the API’s response format changed?
    No problem! Simply delete the cassette files and re-run the tests and VCR will automatically create the new cassette files for you.

    What else?

    In addition to the above mentioned frameworks, we also use the following tools to make sure our tests run fast and report any problem as early as possible:

    • Spork
      Normally when running specs that exercise Rails components (controller, models, etc.) the whole Rails environment needs to be loaded before each spec, which results in a very large overhead, especially if the execution time of the spec itself is very short.
      Spork is a DRb test server that stays running between spec executions which greatly reduce the time it takes to run specs.
    • Guard is a file watcher gem that handles events on file system modifications.
      It has many extensions, among them guard-rspec and guard-spork which we use in our day-to-day work.
      Guard-RSpec listens to file modifications events on production code and runs the relevant specs.
      For instance, any time we change app/models/item.rb, guard will run spec/models/item_spec.rb.
      The second extension we use is Guard-Spork which reloads the Spork server whenever a modification is made to Rails environment configuration files (application.rb, spec_helper.rb, etc.).
      There is nothing more irritating than spending 10 minutes debugging a problem and only then realizing that the recent changes you made were not taken in effect. With Guard-Spork you need not worry for it to happen ever again!
    • TeamCity
      Running Guard in a background process certainly reduces the chance of pushing code that breaks the tests, however to be sure that no breaking changes make their way into the production we use TeamCity as our Continuous Integration server.
      The latest versions of TeamCity have solid support for RVM which allows us to deploy projects that use different Ruby versions.

    That’s it for now, cya next time!

    By Ido Feins and Adam Farhi

  • A finite tale of infinite mazes

    Shay July 22, 2012

    To say that we love games is a total understatement. We are also very keen on game development, so it was clear that at some point or another we would end up developing a game. A few weeks ago we conducted an experimental game development Kata. Since you will probably hear us use this word a lot, a quick explanation: We host weekly Katas to practice various coding methods together as a team. The word is from Japanese and is used to describe systematic training methods of combat.

    After an hour of throwing around random ideas we agreed to develop a variation of a Pac-Man game. Instead of having a single level layout, we decided that our Pac-Man maze would be procedural-generated and infinite (i.e. the level never ends). We named it Hobo-Man – a tale of a hobo wandering through endless streets in search for cash.

    We split into three teams: Assets team (sounds graphics), 2D engine team (built on HTML5 canvas) and the data-structure team, which focused on creating and representing the game-world and its entities. This post focuses on the data-structure team’s work and its rather finite struggle to generate infinite mazes.

    First things first – Google. We suspected that an ‘infinite PacMan’ already existed somewhere and we were right. World’s Biggest PacMan (WBP) allows players to append their own levels to an existing, gigantic level-base. Players can start their session from any of those levels and explore others. When the player leaves a level, the adjacent one is loaded instead.

    While  the core idea of WBP is similar to ours, the following features are missing from the game:

    1. It’s not really infinite - There are only around 90k user-generated maze.
    2. It’s not seamless - We wanted to create a single-level experience, without having to load other chunks of the maze each time the player crosses a level’s border.

    Nevertheless, WBP was an inspiration on how to generate our infinite maze. We figured that a good approach would be to generate small chunks (blocks) on-demand, and append them to existing chunks (as in WBP) as the player traverses the maze. By now, we already had the basics of our data-structure:

    1. The world would be represented by a hash-matrix – coordinates are keys, while values are blocks. The hash allows negative coordinate values (for exploring the maze to the top or left).
    2. Each block is a 20×20 matrix of tiles.
    3. A tile can be either a blocking wall, or a passable route.

    Once we had the underlying structure, it was time to move to the really interesting part – the maze generation algorithm. There are many maze generation methods we could have implemented, each which would have created a different kind of maze layout. Most of these algorithms are designed to generate a ‘perfect maze’:

    Mazes containing no loops are known as ‘perfect’ mazes

    …which is clearly not the PacMan way. The player has no reason to perform risky moves into obvious dead-ends in order to earn a few points.

    Eventually we settled on trying our own version of the ‘recursive division method’ algorithm which is very simple:

    Begin with the maze’s space with no walls. Call this a chamber. Divide the chamber with a randomly positioned wall (or multiple walls) where each wall contains a randomly positioned passage opening within it. Then recursively repeat the process on the subchambers until all chambers are minimum sized (taken from the Wikipedia entry).

    Our variant had a little tweak – it doesn’t insert random dead-ends:

    We implemented the algorithm in JavaScript and tested it with our newly rendering engine. And… it looked pretty lame:

    Our recursive division maze. Looks like Tel-Aviv.

     

    We ended up having lots of long boring corridors which were both visually ugly and no fun to traverse. Trying to reducing the block size from 20×20 tiles to 10×10 (and even lower) resulted in even uglier mazes. As a result, we understood that we would have to craft our maze generation method from scratch (which is ultimately more fun).

    And so patterns were born. The maze is generated by 3×3 patterns (or any odd number by odd number). The center tile of each pattern is always passable by the player, and the pattern has 4 flags determining whether its top, bottom, left or right paths are passable.

    The maze beings with single 3×3 tiles pattern. All patterns are generated with a passable center tile. A pattern can have a passable route only in its top, bottom, left or right tiles. The corners will always be walls.
    Each pattern must have an entrance and an exit (to prevent dead-ends). Two directions are chosen randomly and are set as passable routes. A pattern can have more than two routes, yet the probability for more is low.
    A new pattern is added upon request (for example, by the renderer, or an entity that moves around the maze). New patterns are saved in the hash-matrix so they can be used by future requests.
    The new pattern has to connect to any existing neighbor pattern in order to extend existing routes. It sees that the neighbor pattern has a route to the right, so it creates a connection on its left side.
    Because the new pattern connected only to a single pattern, a new direction must be opened in order to reach the requirement of at least two passable routes.
    In this example, despite the low probability, the pattern created another passable route to the top. The probability of another, fourth route, is very low.
    Another pattern is added in the same process: It is connected to the top pattern, another passable route is added in order to have the two mandatory routes, and then a third route is being chosen randomly. Again, due to the low probability of having a fourth route, it is not added.
    The last pattern is added. Due to its neighbors adjacent connections, it automatically connects to the top and to the left. The pattern is unlucky, and doesn’t random any other independent passable routes.

    On large scales and with the right probabilities, we eventually got to an infinite maze with almost zero unconnected loops:

    An example of the final version

    Initially, the cells were not stored individually in our data structure. They were being brought lazily from the patterns (computed per request). When the renderer asked for a certain cell, we first found its parent pattern, and then its positions inside the pattern. We created a new cell object based on the attributes of the pattern. We realized we need to store the cell in a different hash-matrix in order to store their contents (powerups and coins) and also in order to add new features. We kept the patterns hash-matrix so we could easily create new patterns and connect them to existing ones using a simple API.

    This power-up allows the player to break through walls.

     

    With our mazes and awesome graphics completed, Hobo-Man was ready to venture the endless city and collect coins. You can experiment with Hobo-Man and its code below:

    Play HoboMan | Source code

     

    Tags: Hoboman, Kata

Geeks, Not Ninjas is the eBay Israel Innovation Center's blog about development, product and other cool stuff we do.

  • About us
  • Jobs
We're hiring!


See open positions

Recent posts

  • Farewell to ISC’s Rock Star Ninja Coders
  • Gemifying our way to future projects
  • Trimming the fat from your controllers
  • Testing in the ISC
  • A finite tale of infinite mazes
  • Hello Boulevard!
Subscribe to our feed
Tweets about "#notninjas"