There is no cloud

there-is-no-cloud

Advertisements

Being user 137 on StackOverflow

It’s funny how SO has become such a big part of our lives as developers.

It’s doubly fascinating for me, because I was there at the birth. Back in 2007 I followed Jeff Atwood and Joel Spolsky’s blogs eagerly; Spolsky, of course, had been an influential tech blogger for many years and reached massive fame for three things; firstly, his company Fog Creek’s popular bug tracker Fogbugz, which many dev teams used routinely. Secondly, Fog Creek’s innovative approach to programmer happiness, like ensuring that every developer had their own office with a door that closes! And thirdly, for the Joel Test, still widely used as a quick objective metric of the quality of a developer team and their processes.

And Atwood? Atwood was always a delightful read; opinionated and funny, and self-deprecating in a way I wish more developers were. His Coding Horror logo, used by permission from Steve McConnell of Code Complete fame, reminds everyone that there is bad code everywhere and much of it is our own; but now we know and try to do better!

So when these two towering figures in the community joined forces and announced they were going to collaborate on a project, of course my ears pricked up. The best thing was, they were going to podcast their weekly project update meetings, since Joel lived in New York and Jeff in California.

Jeff was doing the hands-on work, and for the first few months of the podcast it was hilarious how his estimating (“Oh, 12 to 13 weeks I expect”) style grated with Joel. Of course it took way longer than Jeff thought, but the best bit was seeing the vision unfold; the StackOverflow we see today is not that much changed from how it was after the first six months of work, and we got to experience the decision making process first hand, understanding exactly what lay behind every design decision.

And of course, they were very, very funny to listen to.

When Jeff sent out the first invitations to the Beta, I immediately signed onto the waiting list. And a couple of days later, I got my invite. It felt really special, being one of this elite group of developers from all different disciplines – all collaborating on something to benefit every developer for ever.

So I’m user 137 on StackOverflow. They’re up to over five million now and rising. In the beginning we didn’t have the rules for good questions we have now; we discovered the later rules out of how people used the product and in particular, through Jeff’s excellent judgement about what was beneficial and what was not. We found out pretty early on that questions that solicited lists or subjective judgements were harmful and now such questions are rightly discouraged as low-brow attempts at rep-whoring.

But in the earliest days, I had one goal in mind: to get editing rights, so I could help to improve the questions I saw that needed it and help to curate and preserve this vital body of developer knowledge. And that meant I needed 3,000 reputation, and I did everything I could to earn it while still asking questions that I thought were useful to people.

It took me a while to get there but in a few months I had achieved a reasonable level of editing power and I was content. Real work took me all my time and as thousands of developers began to compete to post the best, quickest answers my useful participations quickly tailed off.

But over the years, those questions from the early days still continue to earn me reputation despite my relative inactivity on the platform. My rep is over 13,000 and it’s all from questions that would never be allowed now. But I’m kind of glad they’re there – they’re part of the social anthropology of the web, and even if they aren’t good questions, every week they’re upvoted by people who don’t know any better but still value them.

So it’s kind of tough now being user 137 – I feel a bit of a fraud because my rep comes from early experiments and earnest rep-whoring of the most well-meaning sort. But I’d never give it up.

Where to put POROs in Rails apps

So, I’ve got this conundrum.

The more I learn about OO design (a journey which started in 2007, mind you!), the more I want to apply what I know about good design in my daily work. But it’s hard, being the sole developer building an MVP for a startup where every second counts. There’s an increasing cognitive dissonance between what I know I want to do, like unit testing, tdd, building small POROs for business logic and so on just like Sandi Metz and Avdi Grimm encourage us to do, and what Rails encourages through its file structure and what I end up doing in practice, which is just throwing another method into the User or CourseModule class and getting the feature out the door.

The conundrum is pretty simple; the Rails way doesn’t of itself lead you to write good code, it encourages you to think about everything within its structure, and doesn’t make obvious places for your own classes outside of Controllers and Models. I want to extract stuff out into single responsibility classes, but if I do that, what about Rails? Rails is the reason I’m using Ruby, after all; I want the productivity and programmer joy that comes from using it. But I also want to develop the craft of software design.

So I was overjoyed to come across this blog post by Vladimir Rybas on just this topic. Here he quickly outlines the problem and describes a few current approaches, most of which just don’t feel rails-y – and more importantly, mean you end up creating a completely custom file structure which makes it really hard to predict where stuff is going to be. That’s one of the joys of Rails, that pretty much everything has a home and that it’s consistent from Rails app to Rails app. It’s such a small but important thing to give up.

It’s his fourth one which hit the spot for me – using namespaces and subdirectories within the existing default Rails directory structure. Here’s a quick summary, but do read his post and his rationale, it’s great.

Here’s one of his examples which shows it in action

class User < ActiveRecord::Base
  include Lockable
  include Settings

  def can_follow?(user)
    FollowingPolicy.new(self, user).can_follow?
  end
end

This is where the files actually live

models
├── user
│ └── following_policy.rb
│ └── lockable.rb
│ └── settings.rb
└── user.rb

And this is the code in each of the files

# app/models/user/lockable.rb
module User::Lockable
  def lock_access!
    update(locked_at: Time.now)
    UserMailer.account_locked_email(self).deliver
  end

  # ...
end

# app/models/user/settings.rb
module User::Settings
  extend ActiveSupport::Concern

  included do
    store_accessor :settings
  end

  # ...
end

# app/models/user/following_policy.rb
class User::FollowingPolicy
  attr_reader :current_user, :other_user, :account_verification

  def initialize(current_user, other_user)
    @current_user = current_user
    @other_user = other_user
    @account_verification = current_user.account_verification
  end

  # ...
end

One stylesheet to rule them all

Very excited to finally think of searching for the browser default style sheet, and here it is:

http://trac.webkit.org/browser/trunk/Source/WebCore/css/html.css

For example:

p {
43 display: block;
44 -webkit-margin-before: 1__qem;
45 -webkit-margin-after: 1__qem;
46 -webkit-margin-start: 0;
47 -webkit-margin-end: 0;
48 }

Turns out a qem here is a “quirks mode em” (Thanks to http://stackoverflow.com/questions/7448673/what-does-1-qem-mean)

Cleaning up submitted emails in Ruby

So there I was the other day, adding a feature where users could invite their friends to join Fluency too. The UI is a textarea where the user is asked to enter the email addresses on separate lines, so that’s pretty simple to grab the emails from:

recipients = params[:contact_emails].split(/\s/)

But because the line separator is actually two characters (newline and carriage return) you end up with empty elements in the returned array:

["someone@example.com","","something@gmail.com"]

Enter Ruby; by passing a block to the array, it can test for empty strings and reject them:

recipients.reject! { |c| c.blank? }

which can be written in a more compact form thus:

recipients.reject!(&:empty?)

So how to check that they are actually emails?

Well, we can monkey patch the String class like so

class String
def looks_like_email
!! self.match(/\A[^@]+@([^@\.]+\.)+[^@\.]+\z/)
end
end

and then use a similar technique by passing a block to the array of cleaned strings to verify that they are indeed emails. The snippet above is a simple test – ensuing that there is a dot and an @ sign with at least one character surrounding them in the right order.

recipients.reject! { |c| not c.looks_like_email }

so for example

["someone@example.com","somethingwrong","something@gmail.com"]
becomes

["someone@example.com","something@gmail.com"]

So finally, what happens if someone enters commas between the items of the list?

Then we end up with them appended to our emails in a way that is very wrong and will wreck everything:

["someone@example.com,","something@gmail.com,"]

To get rid of this, one might think of using something like

recipients = params[:contact_emails].gsub(",",'')

and this would work, but it’s a bit inelegant; as is so often the case, there is an elegant solution built into Ruby, the delete method.

This removes all instances of the characters you pass to it. So for example:

"This is another nice mess you've gotten us into".delete('mess')
=> "Thi i anothr nic you'v gottn u into"

It doesn’t do quite what it looks like it will at first; rather than deleting just the word “mess”, it deletes all the “m”s, all the “e”s, and all the “s”s.

"Thi i anothr nic you'v gottn u into"

So we can simply chain this onto the first line before we call split:

recipients = params[:contact_emails].delete(',').split(/\s/)

Finally, suppose someone enters a list of emails with commas and no spaces? Like this:

something@example.com,somethingelse@example.com

After we delete the commas there will be no white space for the split!

So, let’s just make sure there always are spaces by replacing any commas with a comma and a space.

.gsub(",", ", ")

So the bit of code for our controller ends up like this:

recipients = params[:contact_emails].gsub(",", ", ").delete(',').split(/\s/)
recipients.reject!(&:empty?)
recipients.reject! { |c| not c.looks_like_email }

And it will take a list of email addresses which can either be space separated, comma and space separated, or on new lines and it will return a list of valid-looking emails.

Rails URL helpers in the rails console

Not a day goes by that I don’t find another thing in Rails that delights me and makes life easier. Yesterday it was finding that you can access the Rails application from the rails console by simply calling app:

This returns the entire app instance with all of its methods available to call directly. So helpers you can call in the controller context, you can call on the console as messages to app:

irb(main):190:0> app.manage_posts_path
=> "/manage/posts"

Avoid the Three-state Boolean Problem

Quick, what’s wrong with this Rails migration?

add_column :users, :admin, :boolean

Yep – it can be null. Your Boolean column is supposed to be only true or false. But now you’re in the madness of three-state Booleans: it can be true, false, or NULL.

Awesome post from the genius guys at Thoughtbot. This is how to do booleans in Rails:

add_column :users, :admin, :boolean, null: false, default: false

Avoid the Three-state Boolean Problem.