Wednesday, July 30, 2014

Week of RSpec

This week I've been spending some more time learning RSpec and writing the Connect Four game using TDD approach. While I am not done with the game yet (as of today), I already see that TDD approach forces me to write smaller and more compact methods, aimed at solving one and only task.

I would like to discuss one interesting way that I discovered of accessing variables initiated in an instance of another class. Say, my Connect Four game is very simple and consists of two classes:

class Board
end

class Game

  def initialize
    @board = Board.new
  end

end

I want to test that the Game properly initializes an empty Board. But how to access the Board? One of the options is to make Board visible to the outer world via getters and setters like so:

class Game
   
   attr_accessor :board

   def initialize 
     @board = Board.new
   end

end

In RSpec, one would then write a test like this:

describe "Game": 
  
  let (:game) { Game.new }
  
  it "initializes an empty board" do
    expect(game.board).to be_an_instance_of Board
  end

end

However, there may be situations when it is not desired to expose an object or a variable in this manner. I found the method instance_variable_get(:@your_object) to be useful. Our test can look like so:

describe "Game" do

  let (:game) { Game.new }

  it "initializes an empty board" do
    expect(game.instance_variable_get(:@board)).to be_an_instance_of Board
  end

end 

I realize this may not be the best design decision, as it is possible to wrap a variable you want to test in a method, and then call that method instead, which will return the value. However, it is good to know all available options.

Monday, July 28, 2014

Testing with RSpec

Writing tests for your code is an investment into your own sanity in the future. Frequently, there are many more lines of test code than the actual code. I remember my surprise as I was going through Michael Hartl's Ruby on Rails Tutorial and realizing at some point I was learning more RSpec than Ruby or Rails. At least, it felt like that.

At the moment, my ratio of test code to actual code is still low, but I am getting there. It is also good to follow some best practices in describing tests, as it increases the readability of the code itself as well as the output.

Some good things to follow include using a period in describing a class method, and a pound sign in describing an instance method:

describe ".class_method" end; describe "#instance_method" end

Passing --format documentation as an argument creates a much more readable output results. Thus, running this block

describe Book do


    before :each do

        @book = Book.new "Title", "Author", :category

    end


    describe '#new' do

        it "returns a new book object" do

            @book.should be_an_instance_of Book

        end

    end


    describe "#title" do

        it "returns the correct title" do

            @book.title.should eql "Title"

        end

    end


    describe "#author" do

        it "returns the correct author" do

            @book.author.should eql "Author"

        end

    end


    describe "#category" do

        it "returns the correct category" do

            @book.category.should eql :category

        end

    end


end


returns results nicely formatted as follows:

Book

  #new

    returns a new book object

  #title

    returns the correct title

  #author

    returns the correct author

  #category

    returns the correct category


These things have been added to my arsenal.

Friday, July 25, 2014

One course is over; more are to come

This week is the last week for CS169.2x class, offered through edX. I am very glad that I took this class (including CS169.1x before). It was a very intensive adventure, and particularly useful as it created an opportunity for hands-on exercises and pair programming with people from all over the world; an opportunity to learn about Agile software development, legacy code and other tips and tricks that are often missed in a purely academic environment.

There was some time spent on how to read, analyze and refactor legacy code, and I consider this to be one of the most useful parts of the course. On this note, I'd like to mention the railroady gem, which allows to create simplified Unified Modeling Language class diagrams in order to analyze the the relationships among the most important classes and attributes. I think it is a good gem to use in one's own code at some point - for an inexperienced developer, it can be so easy to get tangled up in classes and relationships. Railroady gem might just be the tool to help get your head out of the mess.

It is sad to see an adventure to have come to an end, but there are more just around the corner. I plan on continuing to enhance my education through online courses, and the next one is coming up through Coursera - Web Application Architectures. Compared to CS169, it might be a step down in terms of complexity of the material, but repetition is the mother of all learning. I am also looking forward to Introduction to Functional Programming, a new course offered through edX. The course uses Haskell, and it'll be fun to learn it.

It will be great to see any CS169 classmates in these and other courses.

Wednesday, July 23, 2014

Masonry and Pagination

Recently I've decided to add Pinterest-style layout and infinite scrolling of images to the main page of one of my apps. (I may decide not to keep it later on, but hey, this is a good learning experience, right?)

I've done my homework and settled with a gem called kaminari for pagination, and Masonry, a JS grid layout library. Due to the popularity of dynamic layouts, a lot of code examples are available. Based on those, my snippets look like so (in index.html.erb):

<div class="masonry-container">
  <% @contents.each do |content| %>
   <div class="masonry-item">
     <%= image_tag content.image.url(:original) %>
    </div>
  <% end %>
</div>
<%= paginate @contents %>

and in application.js:

$(function()
{
    var $container = $('.masonry-container');
    $container.masonry({
        isFitWidth: true,
        //columnWidth: '.masonry-item',
        itemSelector: '.masonry-item'
        }).imagesLoaded(function(){
            $container.masonry('reload');
    });

    $container.infinitescroll({
            navSelector  : "nav.pagination",
            nextSelector : "nav.pagination a[rel=next]",
            itemSelector : ".masonry-container div.masonry-item",
        },
        function(newElements) {
            var $newElems = $(newElements).css({opacity: 0});
            $newElems.imagesLoaded(function(){
                $newElems.animate({opacity: 1});
                $container.masonry('appended', $newElems, true);
            });
        }
    );
});

I was generally happy with the behavior of my scrolling except for several things.
  1. I wanted to center and distribute all images in the main container evenly, for which Masonry provides an option isFitWidth: true. As I discovered, you can't use the option columnWidth at the same time (that's why it is commented), as this combination appears to stack all images on top of each other. (I guess, I didn't read the documentation well enough but it took me some time to discover the cause).
  2. The images I was loading differed in height quite a bit and perhaps for this reason they were not distributed as nicely as I wanted them to; there was too much white space vertically for my taste. Until I can find a better solution, I am settling with the following:
    • Paperclip gem for image uploading allows to serialize the image dimensions and to store them in the database;
    • One can create a scope, where the results will be sorted by height in a descending order. The scope will be used in controller to filter the results like so:

    • scope :by_height, ->   { order('height DESC') }
      @contents = Content.all.by_height.page(params[:page])
      

    Sorting the images in descending order beforehand gave me the desired look: very nicely and tightly stacked images with much less white space in between.
  3. As you scroll down and images are being loaded, you are supposed to be getting a message at the end of the current window saying something like "More images are being loaded....". My message somehow got attached to the top of the page, not the bottom. I wonder what combination of the CSS rules and/or other factors could be causing this behavior. In the meantime, I'm fixing the position of that element forcefully:

  4. #infscr-loading{
      position:fixed;
      bottom: 0;
    }
    

In conclusion: that was fun.

Monday, July 21, 2014

JS: first-class objects

When I come across new material, I frequently like to tell the same information to myself using different words. It just helps to understand it much better.

In the last weeks of CS169.2x class, discussion touched upon Javascript and first-class objects. Javascript functions are first-class object, which means that they can be passed as arguments to other functions, returned as values from other functions, be a part of a data structure or assigned as variables.

What does this look like? A simplified example based on the lectures/the book will look like this:

var Square = function(side){
    this.side = side;
    this.result = function(){
       return this.side * this.side;
    }
}

Square works as a constructor and creates a new object when we call it using the word new:

my_square = new Square(2);

We can then call the result function like this (keeping parenthesis is important):

my_square.result();

As such, this creates a new object whose properties are initialized in the constructor, and we then can return a value from the result function.

There is much more to this, of course. This is a short explanation based solely on my understanding of the CS169.2x materials up to date. Javascript is a huge, vast land, and I am looking forward to exploring its vastness and digging further into details.

Friday, July 18, 2014

Dropbox API

I wanted to use Dropbox for the app I am currently working on. The general purpose of the app is to share (i.e. make public) or not to share (i.e. keep private) photos and videos, and the intended audience is social workers and speech language pathologists. So I needed a way to store the data somewhere. I decided to try Dropbox API, even though I already think that Dropbox may not be a good solution for my purposes, and I may want to use AWS instead. However, since the app is very much in early stages of development, experimenting with different APIs is a great idea.

I was particularly interested in how to obtain a shared link to an image, and there is a method called /shares. It takes path of a file as a parameter and returns a shortened url by default. According to Core API documentation, short_url parameter is optional and when it is set to false, the method returns a long url, which links directly to the preview page.


Ruby SDK didn't use to support this parameter up until a month ago. The method looked as follows (copied from their dropbox_sdk.rb):

def shares(path)
    response = @session.do_get "/shares/#{@root}#{format_path(path)}"
    Dropbox::parse_response(response)
end

It's been updated to the following:

def shares(path, short_url=true)
    response = @session.do_get "/shares/#{@root}#{format_path(path)}", 
                               {"short_url"=>short_url}
    Dropbox::parse_response(response)
end

I've noticed that neither RubyGems nor the official link to Ruby SDK carried an updated version as of today. Perhaps, there is some lengthy review/approval period? In the meantime, I've simply copied the updated method into my own SDK.

Wednesday, July 16, 2014

RailsBridge

Recently I had an opportunity to attend a Front-End workshop organized by RailsBridge. It was my first event with this organization, and I look forward to coming back and learning more about the Front-End technologies, as well as Ruby and Rails. I was impressed by how supportive the environment was, and I already want to come back as a volunteer to help teach a class. Watch out!

After the workshop, one of the teachers - Andre - helped me to debug some old code of mine. In the very early days of learning HTML/CSS/Javascript/jQuery, I created a small project, where a user could press a button and a grid made of div elements would be displayed. The user would then hover over the grids and discover a hidden picture. 

The animation worked as expected in Safari and Chrome but not in Firefox. The grid was supposed to have 35 div elements on each side, and the main wrapping element was set to 960 pixels in width. For some reason, Firefox was displaying a 36th row consisting of just one div. That's how I learned that there are differences in how various browsers round pixels in fluid grids.

A proposed solution was to increase the total page width from 960 to 961 pixels, which took care of the rounding errors so that the proper number of div elements was displayed in all three browsers. Rounding errors is something I will keep an eye on from now on in future work.

Monday, July 14, 2014

The Beginnings

I used to make stone tools and now I make web tools. 

People frequently ask me how I chose to make a shift from being an archaeologist and urban planner to a web developer (well, an aspiring one at the moment of writing). I have thus decided to start a blog, in which I could document my journey to becoming a developer. I could have started writing much earlier, as I already have been learning how to code for a while but oh well. Better late than never, correct? 

Back to the beginnings: what is the connection between stone tools and web tools? I first started writing Python code here and there back in my archaeology days in order to automate processing data and creating GIS maps. Later on, in my urban planning days, I became interested in agent-based modeling and learned NetLogo language. Since then, I've been working at the intersection of social sciences and programming, doing social data analysis and simultaneously developing NetLogo tools for data processing and visualization. Today, it is time to close the gap and get a full immersion in tool-making. Web making.

I am currently a student of The Odin Project, a great place that provides a structured and well-defined path to becoming a web developer with an emphasis on Ruby and Ruby on Rails. The curriculum is free and open-source, and students are welcome to contribute to the project. With freedom comes responsibility - you have to be dedicated, hard-working and diligent in order to succeed in a self-paced learning environment. I can't complain about the lack of these qualities.

The Odin Project is not the only resource I use for obtaining knowledge and experience. MOOCs are such a great place to learn, and I just can't emphasize enough the importance of education accessible to all. I have already completed the first part of CS169: Engineering Software as a Service through edX, and am currently working on the second part of the course. I plan on continuing taking computer science and software engineering courses through edX, Coursera, Udemy, and others. What I love about software is the perpetual learning.

So stay tuned. I will be posting about my progress here. Hopefully, in several months I will have one, or two, or more RoR apps under my belt.