We're looking for an awesome Ruby developer to join our team. Get more details at http://devver.net/jobs.
-
We’re hiring!
-
Boulder CTO Lunch with Matt McAdams
Dan usually goes to the Boulder CTO lunches, but he was out of town this month, which meant I had the pleasure of hanging out with some of Boulder's best and brightest.
This month's guest was Matt McAdams of TrackVia. TrackVia is an online database that is powerful yet simple enough to be used by people who are used to keeping data in spreadsheets (primarily business people). Matt gave a candid and often hilarious talk that touched on both both technical topics, and, luckily for me, a discussion of pricing and metrics, which are two topics that I'm currently very interested in.
On technology decisions:
Matt wasn't a database guy originally, but used his practical knowledge he gained working on a previous startup
Went with the simplest design that could work and it's continued to scale well
Smart technology decisions have allowed TrackVia to compete with a small, lean development team
On product development:
TrackVia started as a contract project for a single customer, but they saw the broader appeal
One of the earliest databases in TrackVia is the bug database (still around). In other words, they've been dogfooding since day one.
They don't worry about the competition. Instead, they focus on building the features that get people to sign up and pay.
On pricing:
You've got try stuff and iterate. TrackVia has changed their pricing several times.
Customers on the old pricing models have always been grandfathered in.
Sometimes raising your price can actually gain customers because some people assume that a cheap product or service must be low-quality (even if it's actually very high quality).
If big customers really want feature X, it's OK to ask them to pay extra to accelerate the development of that feature (or to customize their experience).
On metrics:
Good metrics allow you to try different strategies and measure their effect.
You must measure, tweak, and iterate.
If you can iterate on a weekly basis and your competition can iterate on a quarterly basis, you'll win.
Metrics must continually be improved. TrackVia spends a lot of time tracking useful metrics, but even they know they need to add additional metrics in some key areas.
As usual, the CTO lunch was a great place to hear from other Boulder companies and I learned a lot. Thanks for everyone who attended and special thanks to Matt for leading our discussion. -
Devver.net has a new look!
Tonight we just launched the brand new version of Devver at http://devver.net. It's not perfect (yeah, yeah, we know the blog doesn't match - that should be fixed in the next week or so), but we're trying to "release early, release often." Let us know how you like the new look and how we can improve it!
-
Our Tools & Practices for Remote Collaboration
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
disruptiveMore
disruptiveChannel 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?
-
The newest member of the Devver team
Dan and I are very excited to welcome Avdi Grimm to our small team here at Devver. Avdi has over ten years of professional experience working at Raytheon and MDLogix and has created and contributed to a number of open-source projects. He shares our vision of bringing developer tools to the cloud, our goal of using testing to consistently deliver high-quality software, and our commitment to openness between our company, our users, and the community at large. Welcome, Avdi!
-
Lessons learned from our hiring process
We're very happy to announce that we've had a great developer accept our offer to join our team. We'll have more details on our newest team member soon.
This was our first attempt at hiring and we certainly learned a lot. While our process has improved since we started, it's still a work in progress.
The first lesson we learned is that hiring can take a long, long time - in fact, much longer than we expected. I looked back through my emails and we officially started looking for someone more than four months ago. One thing we have heard time and time again was the importance of hiring only the best people - and, just as importantly, people that fit well within your company culture.
As a result, we were extremely picky when it came to candidates. As the process goes on and on, it's easy to get frustrated and want to lower your bar. Avoid this temptation! If at all possible, go the other route: raise your compensation, improve your pitch, and raise your profile so you can attract candidates that meet or exceed your bar.
When we started, we severely underestimated how long it would take and we overestimated how many applications we'd get. Because of these bad assumptions, we made our first mistake - we chose to slowly "roll out" the announcement that we were hiring. First, we just told friends and mentors. A week or so later, we tweeted and put up a blog post. Later on, we posted on some news sites and newsgroups. And after that, we finally created a job posting at Startuply. Waiting between each step was a waste of time - we should have just broadcast as loudly as we could the first day.
We ended up getting a good number of applications, the vast majority of which were from great programmers. We assumed that going through them would waste a bunch of time. We were wrong. In reality, it was really easy to turn down many applications just from their resume (usually the applicant was good, but didn't have the skill set we were looking for). Phone calls were a bit more time-consuming, but were never a waste of time. We always enjoyed talking to candidates, always found a way to improve our process, and usually learned something new about the Ruby ecosystem.
One thing that we improved on was learning to say "no" quickly. Even with the manageable number of candidates we talked to, it was important say "no" as soon as we discovered something that wouldn't fit. Early on, we were a bit hesitant to do so and ended up continuing our process for too long. That wasn't fair to either ourselves or the candidates. It became easier to shut things down quickly once we had interviewed a few people and started to gain confidence that new applications would show up, even if the queue was currently empty.
We also learned that it's important to have a fairly short process. Of course, the biggest priority is to have a process that lets you learn enough about a candidate to be confident in your decision. That said, as you improve, you'll find that you can shorten your process while maintaining your confidence. Shortening the process is better for you (less time spent) and better for your candidates.
The initial version of our process went something like this:
- Check resume, blog, Github account
- Introductory phone call to learn about candidate and convince them Devver is cool
- Second phone call to ask some high-level technical questions
- Ask for and call references
- Remotely pair on a project for a few hours with the candidate
- Fly candidate out to Boulder to meet and discuss technical and business issues
The final version was a bit more compressed:
- Check resume, blog, Github account
- Phone call to learn about them, introduce ourselves, and cover high-level technical questions
- Ask for and call references
- (In parallel with #3) Ask candidate to write small Ruby application and review their code
- Fly candidate out to do some pair programming and discuss technical and business issues
All in all, it was a good (if sometimes painful) learning experience. We deeply appreciate the time and effort spent by every single applicant (and their patience with us as we learned by trial and error).
If you've got your own lessons you've learned while hiring, please let us know. We know we've still got a lot to learn...
-
Devver.net in closed beta!
Today we released the beta version of Devver.net to our initial set of users. This release is a major milestone: while our alpha release showed that the concept could work, it didn't have the security or scalability for real-world use. This beta is a solid foundation for us to build on in the months ahead.
We're happy to have this release out, but it was certainly a difficult experience - we spent over two months on this release, which is more than a month longer than we expected. We've learned a lot from this - most importantly, that it's very difficult to predict the time to complete large releases. We felt it was necessary to make the big changes now, but going forward we'll be moving to much shorter release cycles (every 1-2 weeks).
In the coming months, we'll be looking for people to try out our beta. If you have a slow Ruby Test::Unit test suite that you'd like to speed up, contact us and we'll put you on our list.
-
Using Ruby to Send Update Emails to Our Mentors
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.net is hiring!
We are looking for a top-notch Ruby hacker who wants to help us build the next generation of developer tools.
At Devver.net, you'll be solving new and interesting problems on a daily basis. You'll help us improve our architecture and build new features.
If you have a passion for Ruby, developer tools, and highly distributed systems, please read more about the job and contact us at jobs@devver.net
-
Building a iPhone web app in under 50 lines with Sinatra and iUI
One awesome thing about the iPhone is that it can display documents very nicely, including Word, Excel, and PDF files. However, the other day I was complaining that it's not very easy to view the documents you store on your computer on your iPhone. Sure, you could email them to yourself, but then you have to search through your mail on your iPhone to find your documents. And I'm sure there is a snazzy iPhone app from the App Store to do this as well. But instead, let's build a quick web app using Sinatra and iUI.
Here's what we'll be building (screenshot courtesy of iPhoney, which rules, by the way):
Sinatra is a really awesome minimalist web framework. It lets you build web applications with just a few lines of code. iUI is a collection of JavaScript, CSS, and images that lets you easily make your web sites look great on the iPhone. Using these two tools, it's really easy to build simple iPhone apps.
To begin, install the Sinatra gem:
> gem install sinatra
Now, let's start with a simplest version of our app, which we'll call 'butler'. Let's make a directory for butler.
> mkdir butler
> cd butler
> touch butler.rb
Open up butler.rb in your favorite editor and type:
Now start butler on your command line:
> ruby -rubygems ./butler.rband point your browser to http://localhost:4567 (you can use your computer's browser or the one on your iPhone - it doesn't matter. I find it's better to use the one on my computer while building the app, since it's easier to read Sinatra's debugging messages if something goes wrong). You should see a page that just says "Your files, sir." Congrats! You've made your first Sinatra app. Wasn't that easy?OK, let's make butler a little more useful. Sinatra will serve up any files in a subdirectory named
public. Since we'll eventually be using thispublicdirectory for holding other JavaScript and CSS files as well, we'll actually put our files in./public/files. We'll also make a link for convenience. Finally, while we're at it, let's put a few test files in there.> mkdir -p public/files
> ln -s public/files files
> echo "foo" > public/files/foo.txt
> echo "bar" > public/files/bar.txtWe want butler to link to each file, so let's build a little helper for that. In Sinatra, you can include helpers within a
helperblock. We'll also try out our helper for one file.Go refresh your browser to see the changes. There's no need to restart your application, because Sinatra automatically reloads changes (very cool!). You should see a link to
foo.txt. Click on it, and you'll see the contents.Clearly, we don't want to hardcode this for just one file. Let's alter butler to look for every file within the
./filesdirectory.OK, refresh your browser and you should see both foo.txt and bar.txt. This is looking pretty good, but we're not really creating valid HTML right now. We're missing
html,head, and,bodytags at the very least. We could add this all within our "get" handler, but that would clutter up the code.Instead, let's put this code into a view. Sinatra actually lets you put the view right after your other code, so you can build an entire application in one file. For simplicity, I'm going to do that for this tutorial. However, if this approach bothers you (or just messes up syntax highlighting in your editor), rest assured you can place the view code in a
viewsdirectory and it would work the same way.Let's add the view to the end of our file, and use it in our handler. Notice that I name the view 'index' by beginning my declaration with
@@ index- if I wanted a separate file, I would just put it in./views/index.erb(you can also use Haml, if that's your cup of tea). Note I assign@linksin the handler and it automatically is available in the view.Refreshing the browser now isn't really that exciting, since things look the same, but if you wanted, you could easily play around with the view to make things look different.
One glaring problem is that this page isn't very usable on the iPhone itself. That's where iUI comes in. Start by downloading it (URL is in instructions below) to your butler directory, unzipping it, and copying the necessary files into your public directory.
> mkdir iui
> cd iui
> wget http://iui.googlecode.com/files/iui-0.13.tar.gz
> tar -xzvf iui-0.13.tar.gz
> cd ..
> mkdir public/images
> cp iui/iui/*.png public/images
> cp iui/iui/*.gif public/images
> mkdir public/javascripts
> cp iui/iui/*.js public/javascripts
> mkdir public/stylesheets
> cp iui/iui/*.css public/stylesheets
To use iUI, you'll need to include the JavaScript and CSS in your view. You'll also need to add some elements to the body of your view. When you're done, the view will look like this:
This html is probably a bit confusing, but don't worry. There are a few examples in
./iui/samples/to learn from (and good iUI tutorials on the web). Finally, you'll want to alter thefile_linkhelper to print out iUI code, like so:Note that
target='_self'code. You need that to get iUI to open a link in a normal way. If you leave it off, it will use an AJAX call to load the file within the current page, which looks really funny when you try to open a binary file like a PDF.The final code looks like this:
And there you have it - an iPhone web app in less than 50 lines of code, thanks to Sinatra and iUI. Now, whenever you want to view some files on your iPhone, either copy the file:
> cp path/to/my_file ./filesor if you prefer, link it:
ln -s path/to/my_file ./files... and then run butler
ruby -rubygems ./butler.rbFigure out the IP address of your computer and simply point your iPhone browser to
http://<ip>:4567I use butler primarily within my home network, but if you want to be able to view your files on the go, you'll need to poke a hole in your firewall. That's a bit outside the scope of this tutorial, but a quick Google search should give you some good results.
Enjoy!
Update: Removed an unused parameter from the code after pmccann called it to my attention.
Update: Added -z option totarafter Peter pointed out the omission. Thetarcommand without -z worked for me on OS X 10.5, but this is definitely more correct.
Update: Added -rubygems option torubycommand. If you'd prefer to not use this option, check the comments below for ways to use RubyGems in a Ruby script.

