• Announcing Caliper Community Statistics

    by Ben

    For the past few months, we've been building Caliper to help you easily generate code metrics for your Ruby projects. We've recently added another dimension of metrics information: community statistics for all the Ruby projects that are currently in Caliper.

    The idea of community statistics is two-fold. From a practical perspective, you can now compare your project's metrics to the community. For example, Flog measures the complexity of methods. Many people wonder exactly defines a good Flog score for an individual method. In Jake Scruggs' opinion, a score of 0-10 is "Awesome", while a score of 11-20 is "Good enough". That sounds correct, but with Caliper's community metrics, we can also compare the average Flog scores for entire projects to see what defines a good average score.

    To do so, we calculate the average Flog method score for each project and plot those averages on a histogram, like so:

    flog_average_method_histogram

    Looking at the data, we see that a lot of projects have an average Flog score between 6 and 12 (the mean is 10.3 and the max is is 21.3).

    If your project's average Flog score is 9, does that mean it has only "Awesome" methods, Flog-wise? Well, remember that we're looking at the average score for each project. I suspect that in most projects, lots of tiny methods are pulling down the average, but there are still plenty of big, nasty methods. It would be interesting to look at the community statistics for maximum Flog score per project or see a histogram of the Flog scores for all methods across all projects (watch this space!).

    Since several of the metrics (like Reek, which detects code smells) have scores that grow in proportion to the number of lines of code, we divide the raw score by each project's lines of code. As a result, we can sensibly compare your project to other projects, no matter what the difference in size.

    The second reason we're calculating community statistics is so we can discover trends across the Ruby community. For example, we can compare the ratio of lines of application code to test code. It's interesting to note that a significant portion of projects in Caliper have no tests, but that, for the projects that do have tests, most of them have a code:test ratio in the neighborhood of 2:1.

    code_to_test_ratio_histogram

    Other interesting observations from our initial analysis:
    * A lot of projects (mostly small ones) have no Flay duplications.
    * Many smaller projects have no Reek smells, but the average project has about 1 smell per 9 lines of code.

    Want to do your own analysis? We've built a scatter plotter so you can see if any two metrics have any correlation. For instance, note the correlation between code complexity and code smells.

    Here's a scatter plot of that data (zoomed in):

    scatter_plot

    Over the coming weeks, we'll improve the graphs we have and add new graphs that expose interesting trends. But we need your help! Please let us know if you spot problems, have ideas for new graphs, or have any questions. Additionally, please add your project to Caliper so it can be included in our community statistics. Finally, feel free to grab the raw stats from our alpha API* and play around yourself!

    * Quick summary: curl http://api.devver.net/metrics for JSON, curl -H 'Accept:text/x-yaml' http://api.devver.net/metrics for YAML. More details. API is under development, so please send us feedback!

    Devver Caliper: Hosted metric_fu for your Ruby project.
    Get set up in under a minute

    Posted on November 19th, 2009 by Ben in Development, Ruby, Tools and tagged , .

  • Improving Code using Metric_fu

    by Dan

    Often, when people see code metrics they think, "that is interesting, I don't know what to do with it." I think metrics are great, but when you can really use them to improve your project's code, that makes them even more valuable. metric_fu provides a bunch of great metric information, which can be very useful. But if you don't know what parts of it are actionable it's merely interesting instead of useful.

    One thing when looking at code metrics to keep in mind is that a single metric may not be as interesting. If you look at a metric trends over time it might help give you more meaningful information. Showing this trending information is one of our goals with Caliper. Metrics can be your friend watching over the project and like having a second set of eyes on how the code is progressing, alerting you to problem areas before they get out of control. Working with code over time, it can be hard to keep everything in your head (I know I can't). As the size of the code base increases it can be difficult to keep track of all the places where duplication or complexity is building up in the code. Addressing the problem areas as they are revealed by code metrics can keep them from getting out of hand, making future additions to the code easier.

    I want to show how metrics can drive changes and improve the code base by working on a real project. I figured there was no better place to look than pointing metric_fu at our own devver.net website source and fixing up some of the most notable problem areas. We have had our backend code under metric_fu for awhile, but hadn't been following the metrics on our Merb code. This, along with some spiked features that ended up turning into Caliper, led to some areas getting a little out of control.

    Flay Score before cleanup

    When going through metric_fu the first thing I wanted to start to work on was making the code a bit more DRY. The team and I were starting to notice a bit more duplication in the code than we liked. I brought up the Flay results for code duplication and found that four databases models shared some of the same methods.

    Flay highlighted the duplication. Since we are planning on making some changes to how we handle timestamps soon, it seemed like a good place to start cleaning up. Below are the methods that existed in all four models. A third method 'update_time' existed in two of the four models.

     def self.pad_num(number, max_digits = 15)
        "%%0%di" % max_digits % number.to_i
      end
    
      def get_time
          Time.at(self.time.to_i)
      end
    

    Nearly all of our DB tables store time in a way that can be sorted with SimpleDB queries. We wanted to change our time to be stored as UTC in the ISO 8601 format. Before changing to the ISO format, it was easy to pull these methods into a helper module and include it in all the database models.

    module TimeHelper
    
      module ClassMethods
        def pad_num(number, max_digits = 15)
          "%%0%di" % max_digits % number.to_i
        end
      end
    
      def get_time
          Time.at(self.time.to_i)
      end
    
      def update_time
        self.time = self.class.pad_num(Time.now.to_i)
      end
    
    end
    

    Besides reducing the duplication across the DB models, it also made it much easier to include another time method update_time, which was in two of the DB models. This consolidated all the DB time logic into one file, so changing the time format to UTC ISO 8601 will be a snap. While this is a trivial example of a obvious refactoring it is easy to see how helper methods can often end up duplicated across classes. Flay can come in really handy at pointing out duplication that over time that can occur.

    Flog gives a score showing how complex the measured code is. The higher the score the greater the complexity. The more complex code is the harder it is to read and it likely contains higher defect density. After removing some duplication from the DB models I found our worst database model based on Flog scores was our MetricsData model. It included an incredibly bad high flog score of 149 for a single method.

    File Total score Methods Average score Highest score
    /lib/sdb/metrics_data.rb 327 12 27 149

    The method in question was extract_data_from_yaml, and after a little refactoring it was easy to make extract_data_from_yaml drop from a score of 149 to a series of smaller methods with the largest score being extract_flog_data! (33.6). The method was doing too much work and was frequently being changed. The method was extracting the data from 6 different metric tools and creating summary of the data.

    The method went from a sprawling 42 lines of code to a cleaner and smaller method of 10 lines and a collection of helper methods that look something like the below code:

      def self.extract_data_from_yaml(yml_metrics_data)
        metrics_data = Hash.new {|hash, key| hash[key] = {}}
        extract_flog_data!(metrics_data, yml_metrics_data)
        extract_flay_data!(metrics_data, yml_metrics_data)
        extract_reek_data!(metrics_data, yml_metrics_data)
        extract_roodi_data!(metrics_data, yml_metrics_data)
        extract_saikuro_data!(metrics_data, yml_metrics_data)
        extract_churn_data!(metrics_data, yml_metrics_data)
        metrics_data
      end
    
      def self.extract_flog_data!(metrics_data, yml_metrics_data)
        metrics_data[:flog][:description] = 'measures code complexity'
        metrics_data[:flog]["average method score"] = Devver::Maybe(yml_metrics_data)[:flog][:average].value(N_A)
        metrics_data[:flog]["total score"]   = Devver::Maybe(yml_metrics_data)[:flog][:total].value(N_A)
        metrics_data[:flog]["worst file"] = Devver::Maybe(yml_metrics_data)[:flog][:pages].first[:path].fmap {|x| Pathname.new(x)}.value(N_A)
      end
    

    Churn gives you an idea of files that might be in need of a refactoring. Often if a file is changing a lot it means that the code is doing too much, and would be more stable and reliable if broken up into smaller components. Looking through our churn results, it looks like we might need another layout to accommodate some of the different styles on the site. Another thing that jumps out is that both the TestStats and Caliper controller have fairly high churn. The Caliper controller has been growing fairly large as it has been doing double duty for user facing features and admin features, which should be split up. TestStats is admin controller code that also has been growing in size and should be split up into more isolated cases.

    churn results

    Churn gave me an idea of where might be worth focusing my effort. Diving in to the other metrics made it clear that the Caliper controller needed some attention.

    The Flog, Reek, and Roodi Scores for Caliper Controller:

    File Total score Methods Average score Highest score
    /app/controllers/caliper.rb 214 14 15 42

    reek before cleanup

    Roodi Report
    app/controllers/caliper.rb:34 - Method name "index" has a cyclomatic complexity is 14.  It should be 8 or less.
    app/controllers/caliper.rb:38 - Rescue block should not be empty.
    app/controllers/caliper.rb:51 - Rescue block should not be empty.
    app/controllers/caliper.rb:77 - Rescue block should not be empty.
    app/controllers/caliper.rb:113 - Rescue block should not be empty.
    app/controllers/caliper.rb:149 - Rescue block should not be empty.
    app/controllers/caliper.rb:34 - Method name "index" has 36 lines.  It should have 20 or less.
    
    Found 7 errors.
    

    Roodi and Reek both tell you about design and readability problems in your code. The screenshot of our Reek 'code smells' in the Caliper controller should show how it had gotten out of hand. The code smells filled an entire browser page! Roodi similarly had many complaints about the Caliper controller. Flog was also showing the file was getting a bit more complex than it should be. After picking off some of the worst Roodi and Reek complaints and splitting up methods with high Flog scores, the code had become easily readable and understandable at a glance. In fact I nearly cut the Reek complaints in half for the controller.

    Reek after cleanup

    Refactoring one controller, which had been quickly hacked together and growing out of control, brought it from a dizzying 203 LOC to 138 LOC. The metrics drove me to refactor long methods (52 LOC => 3 methods the largest being 23 LOC), rename unclear variable names (s => stat, p => project), move some helpers methods out of the controller into the helper class where they belong. Yes, all these refactorings and good code designs can be done without metrics, but it can be easy to overlook bad code smells when they start small, metrics can give you an early warning that a section of code is becoming unmanageable and likely prone to higher defect rates. The smaller file was a huge improvement in terms of cyclomatic complexity, LOC, code duplication, and more importantly, readability.

    Obviously I think code metrics are cool, and that your projects can be improved by paying attention to them as part of the development lifecycle. I wrote about metric_fu so that anyone can try these metrics out on their projects. I think metric_fu is awesome, and my interest in Ruby tools is part of what drove us to build Caliper, which is really the easiest way try out metrics for your project. Currently, you can think of it as hosted metric_fu, but we are hoping to go even further and make the metrics clearly actionable to users.

    In the end, yep, this is a bit of a plug for a product I helped build, but it is really because I think code metrics can be a great tool to help anyone with their development. So submit your repo in and give Caliper hosted Ruby metrics a shot. We are trying to make metrics more actionable and useful for all Ruby developers out, so we would love to here from you with any ideas about how to improve Caliper, please contact us.

    Devver Caliper: Hosted metric_fu for your Ruby project.
    Get set up in under a minute

    Posted on October 27th, 2009 by Dan in Development, Devver, Hacking, Misc, Ruby, Testing, Tools and tagged , , , , , .

  • A Dozen (or so) Ways to Start Subprocesses in Ruby: Part 3

    by Avdi

    In part 1 and part 2 of this series, we took a look at some of Ruby's built-in ways to start subprocesses. In this article we'll branch out a bit, and examine some of the tools available to us in Ruby's Standard Library. In the process, we'll demonstrate some lesser-known libraries.

    Helpers

    First, though, let's recap some of our boilerplate code. Here's the preamble code which is common to all of the demonstrations in this article:

    require 'rbconfig'
    
    $stdout.sync = true
    
    def hello(source, expect_input)
      puts "[child] Hello from #{source}"
      if expect_input
        puts "[child] Standard input contains: \"#{$stdin.readline.chomp}\""
      else
        puts "[child] No stdin, or stdin is same as parent's"
      end
      $stderr.puts "[child] Hello, standard error"
      puts "[child] DONE"
    end
    
    THIS_FILE = File.expand_path(__FILE__)
    
    RUBY = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
    

    #hello is the method which we will be calling in a Ruby subprocess. It reads some text from STDIN and writes to both STDOUT and STDERR.

    THIS_FILE and RUBY contain full paths for the demo source file and the the Ruby interpreter, respectively.

    Method #6: Open3

    The Open3 library defines a single method, Open3#popen3(). #popen3() behaves similarly to the Kernel#popen() method we encountered in part 2. If you remember from that article, one drawback to the #popen() method was that it did not give us a way to capture the child process' STDERR stream. Open3#popen3() addresses this deficiency.

    Open3#popen3() is used very similarly to Kernel#popen() (or Kernel#open() with a '|' argument). The difference is that in addition to STDIN and STDOUT handles, popen3() yields a STDERR handle as well.

    puts "6. Open3"
    require 'open3'
    include Open3
    popen3(RUBY, '-r', THIS_FILE, '-e', 'hello("Open3", true)') do
      |stdin, stdout, stderr|
      stdin.write("hello from parent")
      stdin.close_write
      stdout.read.split("\n").each do |line|
        puts "[parent] stdout: #{line}"
      end
      stderr.read.split("\n").each do |line|
        puts "[parent] stderr: #{line}"
      end
    end
    puts "---"
    

    When we execute this code, the result shows that we have captured the subprocess' STDERR output:

    6. Open3
    [parent] stdout: [child] Hello from Open3
    [parent] stdout: [child] Standard input contains: "hello from parent"
    [parent] stdout: [child] DONE
    [parent] stderr: [child] Hello, standard error
    ---
    

    Method #7: PTY

    All of the methods we have considered up to this point have shared a common limitation: they are not very well-suited to interfacing with highly interactive subprocesses. They work well for "filter"-style commands, which read some input, produce some output, and then exit. But when used with interactive subprocesses which wait for input, produce some output, and then wait for more input (etc.), their use can result in deadlocks. In a typical deadlock scenario, the expected output is never produced because input is still stuck in the input buffer, and the program hangs forever as a result. This is why, in previous examples, we have been careful to call #close_write on subprocess input handles before reading any output.

    Ruby ships with a little-known and poorly-documented standard library called "pty". The pty library is an interface to BSD pty devices. What is a pty device? In BSD-influenced UNIXen, such as Linux or OS X, a pty is a "pseudoterminal". In other words, it's a terminal device that isn't attached to a physical terminal. If you've used a terminal program in Linux or OS X, you've probably used a pty without realizing it. GUI Terminal emulators, such as xterm, GNOME Terminal, and Terminal.app often use a pty device behind the scenes to communicate with the OS.

    What does this mean for us? It means if we're running Ruby on UNIX, we have the ability to start our subprocesses inside a virtual terminal. We can then read from and write to that terminal as if our program were a user sitting in front of a terminal, typing in commands and reading responses.

    Here's how it's used:

    puts "7. PTY"
    require 'pty'
    PTY.spawn(RUBY, '-r', THIS_FILE, '-e', 'hello("PTY", true)') do
      |output, input, pid|
      input.write("hello from parent\n")
      buffer = ""
      output.readpartial(1024, buffer) until buffer =~ /DONE/
      buffer.split("\n").each do |line|
        puts "[parent] output: #{line}"
      end
    end
    puts "---"
    

    And here is the output:

    7. PTY
    [parent] output: [child] Hello from PTY
    [parent] output: hello from parent
    [parent] output: [child] Standard input contains: "hello from parent"
    [parent] output: [child] Hello, standard error
    [parent] output: [child] DONE
    ---
    

    There are a few of points to note about this code. First, we don't need to call #close_write or #flush on the process input handle. However, the newline at the end of "Hello from parent" is essential. By default, UNIX terminal devices buffer input until they see a newline. If we left off the newline, the subprocess would never finish waiting for input.

    Second, because the subprocess is running asynchronously and independently from the parent process, we have no way of knowing exactly when it has finished reading input and producing output of its own. We deal with this by buffering output until we see a marker ("DONE").

    Third, you may notice that "hello from parent" appears twice in the output - once as part of the parent process output, and once as part of the child output. That's because another default behaviour for UNIX terminals is to echo any input they receive back to the user. This is what enables you to see what you've just typed when working at the command line.

    You can alter these default terminal device behaviours using the Ruby "termios" gem.

    Note that both STDOUT and STDERR were captured in the subprocess output. From the perspective of the pty user, standard output and standard error streams are indistinguishable - it's all just output. That means using pty is probably the only way to run a subprocess and capture standard error and standard output interleaved in the same way we would see if we ran the process manually from a terminal window. Depending on the application, this may be a feature or a drawback.

    You can execute PTY.spawn() without a block, in which case it returns an array of output, input, and PID. If you choose to experiment with this style of calling PTY.spawn(), be aware that you may need to rescue the PTY::ChildExited exception, which is thrown whenever the child process finally exits.

    If you're interested in reading more code which uses the pty library, the Standard Library also includes a library called "expect.rb". expect.rb is a basic Ruby reimplementation of the classic "expect" utility written using pty.

    Method #8: Shell

    More obscure even than the pty library is Ruby's Shell library. Shell is, to my knowledge, totally undocumented and rarely used. Which is a shame, because it implements some interesting ideas.

    Shell is an attempt to emulate a basic UNIX-style shell environment as an internal DSL within Ruby. Shell commands become Ruby methods, command-line flags become method parameters, and IO redirection is accomplished via Ruby operators.

    Here's an invocation of our standard example subprocess using Shell:

    puts "8. Shell"
    require 'shell'
    Shell.def_system_command :ruby, RUBY
    shell = Shell.new
    input  = 'Hello from parent'
    process = shell.transact do
      echo(input) | ruby('-r', THIS_FILE, '-e', 'hello("shell.rb", true)')
    end
    output = process.to_s
    output.split("\n").each do |line|
      puts "[parent] output: #{line}"
    end
    puts "---"
    

    And here is the output:

    8. Shell
    [child] Hello, standard error
    [parent] output: [child] Hello from shell.rb
    [parent] output: [child] Standard input contains: "Hello from parent"
    [parent] output: [child] DONE
    ---
    

    We start by defining the Ruby executable as a shell command by calling Shell.def_system_command. Then we instantiate a new Shell object. We construct the subprocess within a Shell#transact block. To have the process read a string from the parent process, we set up a pipeline from the echo built-in command to the Ruby invocation. Finally, we ensure the process is finished and collect its output by calling #to_s on the transaction.

    Note that the child process' STDERR stream is shared with the parent, not captured as part of the process output.

    There is a lot going on here, and it's only a very basic example of Shell's capabilities. The Shell library contains many Ruby-friendly reimplementations of common UNIX userspace commands, and a lot of machinery for coordinating pipelines of concurrent processes. If your interest is piqued I recommend reading over the Shell source code and experimenting within IRB. A word of caution, however: the Shell library isn't maintained as far as I know, and I ran into a couple of outright bugs in the process of constructing the above example. It may not be suitable for use in production code.

    Conclusion

    In this article we've looked at three Ruby standard libraries for executing subprocesses. In the next and final article we'll examine some publicly available Rubygems that provide even more powerful tools for starting, stopping, and interacting with subprocesses within Ruby.

    Devver Caliper: Hosted metric_fu for your Ruby project.
    Get set up in under a minute

    Posted on October 12th, 2009 by Avdi in Development, Ruby and tagged , , , , , .

  • Devver adds Postgres and SQLite database support

    by Dan

    We are working hard to quickly expand our compatibility on Ruby projects. With that goal driving us, we are happy to announce support for Postgres and SQLite databases. With the addition of these database options, along with our existing support for MySQL, Devver now supports all of the most popular databases commonly used with Ruby. These three databases are the default databases tested against ActiveRecord and we expect will cover the majority of the Ruby community.

    To begin working with Postgres or SQLite on Devver all you need to do is have a database.yml with the test environment set to the adapter of your choice. If we don't support your favorite database, you can still request a beta invite and let us know which database you want us to support. If we just added support for your database, perhaps we can speed up your project on Devver, so request a beta invite.

    Devver Caliper: Hosted metric_fu for your Ruby project.
    Get set up in under a minute

    Posted on July 6th, 2009 by Dan in Development, Devver, Ruby, Testing and tagged , , .

  • SimpleDB DataMapper Adapter: Progress Report

    by Dan

    From the beginning of Devver, we decided we wanted to work with some new technologies and we wanted to be able to scale easily. After looking at options AWS seemed to have many technologies that could help us build and scale a system like Devver. One of these technologies was SimpleDB. One of the other new things we decided to try was DataMapper (DM) rather than the more familiar ActiveRecord. This eventually let me to work on my own SimpleDB DataMapper adapter.

    Searching for ways to work with SDB using Ruby, we found a SimpleDB DM adapter by Jeremy Boles. It worked well initially but as our needs grew (and to make it compatible with the current version of DM) it became necessary to add and update the features of the adapter. These changes lived hidden in our project's code for awhile, for no other reason than we were too lazy to really commit it all back on GitHub. Recently though there has been a renewed interest about working with on SimpleDB with Ruby. I started pushing the code updates on GitHub, then I got a couple requests and suggestions here and there to improve the adapter. One of these suggestions cam from Ara Howard, who is doing impressive work of his own on Ruby and AWS, specifically SimpleDB. His suggestion on moving from the aws_sdb gem to right_aws, which along with other changes improved performance significantly (1.6x on write, up to 36x on reading large queries over the default limit of 100 objects). Besides performance improvements, we have recently added limit and sorting support to the adapter.

    As I added features, testing the adapter also became slow, (over a minute a run) because the functional tests actually connect to and use SimpleDB. Since Devver is all about speeding up Ruby tests, I decided to get the tests running on Devver. It was actually very easy and sped up the test suite from 1 minute and 8 seconds down to 28 seconds. You can check out how much Devver speeds up the results yourself.

    We are currently using the SimpleDB adapter to power our Devver.net website as well as the Devver backend service. It has been working well for us, but we know that it doesn't cover everyone's needs. Next time you are creating a simple project, give SimpleDB a look, we would love feedback about the DM adapter, and it would be great to get some other people contributing to the project. If anyone does fork my SDB Adapter Github repo, feel free to send me pull requests. Also, let me know if you want to try using Devver as you hack on the adapter, it can really speed up testing, and I would be happy to give out a free account.

    Lastly, at a recent Boulder Ruby users group meet up, the group did a code review for the adapter. It went well and I should finish cleaning up the code and get the improvements suggested by the group committed to GitHub soon.

    Update: The refactorings suggested at the code review are now live on GitHub.

    Devver Caliper: Hosted metric_fu for your Ruby project.
    Get set up in under a minute

    Posted on June 22nd, 2009 by Dan in Amazon Web Services, Development, Ruby and tagged , , , , .

  • Spellcheck your files with Aspell and Rake

    by Dan

    We recently redid our website. The new site included a new design and much more content explaining what we do. We wanted a quick way to check over everything and make sure we didn't miss any spelling errors or typos. First I started looking for a web service that could scan the site for spelling errors. I found spellr.us, which is nice but would only catch errors once they were live. It also can't scan all of the pages which require being logged in.

    I was pairing with Avdi who thought we should just run Aspell, which worked out great. We were originally trying to just create a simple Emacs macro to go through all our HTML files and check them but in the end created simple Rake tasks, which makes it really easy to integrate spellcheck into CI. After Avdi figured out the commands we needed to use on each file to get the information we needed from Aspell, it was easy to just wrap the command using Rake's FileList. To keep everyone on the same setup, we created a local dictionary of words to ignore or accept and keep that checked into source control as well.

    The final solution grabs all the files you want to spell check, then runs them through Aspell with HTML filtering. We have two tasks: one that runs in interactive mode the the user can fix mistakes and one mode for CI that just fails if it finds any errors.

    Devver Caliper: Hosted metric_fu for your Ruby project.
    Get set up in under a minute

    Posted on May 26th, 2009 by Dan in Development, Ruby, Tips & Tricks, Tools and tagged , , , .

  • Single-file Sinatra apps with specs baked-in

    by Avdi

    It's so easy to create little single-file apps in Sinatra that it almost seems a shame to start a second file just for tests.  The other day Dan and I decided to see if we could create a Sinatra app with everything - including the tests - baked right in.  Here's what we came up with.

    The code switches modes on the name of the executable used to run the file. If we run it with the spec command, we get a test run:

    $ spec -fs sinatra-tests-baked-in.rb

    Example App
    - should serve a greeting
    - should serve content as text/plain

    Finished in 0.007221 seconds

    2 examples, 0 failures

    Otherwise, if we call it as a Ruby program, it runs the Sinatra server as we would expect:

    $ ruby sinatra-tests-baked-in.rb
    == Sinatra/0.9.1.1 has taken the stage on 4567 for development with backup from Thin
    >> Thin web server (v1.0.0 codename That's What She Said)
    >> Maximum connections set to 1024
    >> Listening on 0.0.0.0:4567, CTRL+C to stop

    And there you have it: a true single-file application, specs and all.

    Devver Caliper: Hosted metric_fu for your Ruby project.
    Get set up in under a minute

    Posted on May 13th, 2009 by Avdi in Development, Hacking, Ruby and tagged , , .

  • Our Tools & Practices for Remote Collaboration

    by Ben

    Last week, we had Avdi, the newest addition to our team, join us in Boulder, CO. It was great to get some face-to-face time, since Avdi will primarily be working from his home in Pennsylvania while Dan and I continue to work in Boulder.

    We are excited about the benefits of having a distributed team, but we're also aware that there are a number of challenges. As a result, one of the things we worked on last week was figuring out the tools and practices we'll be using to work effectively from across the country. Luckily, both Avdi and Dan have experience working remotely which we can draw upon.

    We evaluated a number of options, but settled on the following tools and practices.

    Practices

    • Daily Standup. Every day at the same time, we all get on video chat. We cover what we did yesterday, what we're working on today, and whether or not we're blocked on anything. The goal is to keep this meeting at 15 min or less.
    • Minimize interruptions. Whenever we need to communicate with each other, we try to do so on the channel that is the least disruptive (and disrupts the fewest team members). Of course, sometimes we need to be disruptive if an issue is pressing, if someone is blocked, or if we need to have high-bandwidth communication (information, especially cues like body language, don't come across very effectively on channels like email)
    • Keep it simple. We want to use the smallest number of tools and channels that will allow us to work effectively.

    Channels and Tools

    Less
    disruptive
    More
    disruptive
    Channel Tool Properties
    Passive Updates Present.ly
    • Asynchronous
    • Not required reading
    Email Any email client (in practice, Gmail)
    • Asynchronous
    • Required reading (usually)
    • Sometimes time-sensitive, sometimes not
    IM Skype
    • Semi-synchronous (but usually synchronous)
    • Usually time-sensitive
    Voice/video chat Skype
    • Synchronous
    • High bandwidth* (especially video chat)
    • Best for meetings

    * By "high bandwidth", I don't mean that the tool itself requires a lot of TCP/IP traffic (although this is true, it doesn't really matter). What I mean is that we can communicate a lot of information between team members in a short amount of time.

    Other Tools

    • Lighthouse for issue tracking
    • GitHub for source control and our project wiki
    • RealVNC for screen sharing (essential for remote pair programming)

    This is our first attempt at finding a good set of tools and practices for remote collaboration. As time goes on, we'll undoubtedly iterate and improve upon these.

    For another perspective (with a slightly different set of tools), here is a presentation from 2008 about virtual teams.

    What tools and practices have worked (and which have not worked) for your team?

    Devver Caliper: Hosted metric_fu for your Ruby project.
    Get set up in under a minute

    Posted on April 28th, 2009 by Ben in Development, Devver, Tips & Tricks, Tools.

  • Managing Amazon EC2 with your iPhone

    by Dan

    I wanted a quick way when out and about to easily manage our AWS EC2 instances while out and about. It hasn't happened often, but occasionally I am away from the computer and I need to reboot the instances. Perhaps I remember our developer cluster isn't being used and want to shut it down to save some money.

    I didn't find anything simple and free with a quick Google search, so in a about an hour I wrote a nice little Sinatra app that will let me view our instances, shutdown, or reboot any specific instance or all of them. The tiny framework actually turned out to be even more useful as I now have options that let us tail error logs, reboot Apache, reboot mongrel clusters, or execute any common system administration task.

    I won't be going into detail on how to build a iPhone webapp using Sinatra and iUI, because Ben already created an excellent post detailing all of those steps. In fact I used his old project as the template when I created this project. I can't begin to explain how amazingly simple it is to build an iPhone webapp using Sinatra, so if you have been thinking of a quick project I highly recommend it.

    Here are some screen shots showing the final app. (screenshot courtesy of iPhoney):

    ec2 manager home view

    ec2 manager home view.

    ec2 manager describe view

    ec2 manager describe instances view.

    ec2 manager instance view.

    ec2 manager instance view.

    This app uses the Amazon EC2 API Tools to do all the heavy lifting. So this app assumes that you already have the tools installed and working on the machine you want this app to run on. This normally involves installing the tools and setting up some environment variables like EC2_HOME, so make sure you can run ec2-describe-instances from the machine. After that you should just have to change EC2_HOME in the Sinatra app to match the path where you installed the EC2 tools.

    Let me know if you have any issues, it is quick and dirty, but I have already found it useful.

    To run the app:
    cmd> ruby -rubygems ./ec2_manager.rb

    Devver Caliper: Hosted metric_fu for your Ruby project.
    Get set up in under a minute

    Posted on March 5th, 2009 by Dan in Amazon Web Services, Development, Hacking, Ruby, Tips & Tricks, Tools and tagged , , , , .

  • Using Ruby to Send Update Emails to Our Mentors

    by Ben

    At Devver.net, we send out weekly email updates to an awesome set of mentors. We do this for a number of reasons. First and foremost, we get valuable feedback and advice from our mentors on a variety of issues. But it's also an easy and effective way to keep us on track and even maximize our chances of success. As Paul Graham says in How Not To Die (he was talking directly to YC teams, but you'll get the idea):

    "For us the main indication of impending doom is when we don't hear from you. When we haven't heard from, or about, a startup for a couple months, that's a bad sign.

    ...

    Maybe if you can arrange that we keep hearing from you, you won't die.

    That may not be so naive as it sounds. ... [The] mere constraint of staying in regular contact with us will push you to make things happen, because otherwise you'll be embarrassed to tell us that you haven't done anything new since the last time we talked."

    Foodzie started emailing their mentors early in the summer. We actually borrowed (stole) their email format and best practices.

    One thing we've tried to not do is send out a completely generic email to all our mentors. Depending on the content and the interaction we've had with a specific mentor, we'll adjust his email accordingly. We begin each email with their name and send it directly to them (in other words, we don't put a huge list of addresses in the To, CC, or BCC fields). We do this because we can tailor it and it helps elicit individual responses from each mentor (it's easier to ignore a question if it's sent to a group).

    But, of course, sometimes the emails to a few mentors can be identical. In this case, my not-so-well-kept secret is that I just use a simple Ruby script to send out a duplicate email that appears to be hand-crafted (or at least copied and pasted).

    I've been told that Outlook can perform this functionality easily, but I don't know of any way to do this within Gmail. If there is, let me know so I can feel a little silly (in any case, the Ruby code was fun to write).

    To run this code, you'll need to install the highline gem. You'll also need to add your Gmail account, recipients, subject message, etc. Finally, you'll want to put your message inside a separate file within project directory. That way, you can easily modify, spellcheck, and format to your heart's content before sending.

    You can get the entire gmailr source code (all two files!) at Github. Please use this script for good, not evil - no one likes a spammer. Enjoy!

    Devver Caliper: Hosted metric_fu for your Ruby project.
    Get set up in under a minute

    Posted on January 20th, 2009 by Ben in Development, Devver, Hacking, Ruby.