Jamie Gaskins

Ruby/Rails developer, coffee addict

Apple Pay Is a Big Deal

Sep 11, 2014 @ 03:03am

I've seen an image in various places around the internet (Twitter, Reddit, even in my Facebook comments) where some guy smugly points out that everything new in the iPhone 6 has been in Samsung phones for almost two years.

iPhone 6 vs Samsung Note 4

I'm not going to try to counter everything he points out there (as much as I'd like to), but instead I'm going to focus on the NFC payments part because that's one of the announcements I liked the most.

Basically, my objection boils down to 3 things:

  • Are NFC payments as easy to use on the Samsung as on the iPhone 6?
  • Are they as secure?
  • How many Android users have actually used that feature?

These are actual questions. I don't have the answers because my only experience with Android phones has been troubleshooting ones that my family and friends have. I'm not saying that to talk shit about them; that's actually the only experience I have with them.

Ease of use

The major selling point in the keynote for Apple Pay was how quick and easy it is to pay for something. You hold your phone up to the sensor and put your finger on the Touch ID panel. Done.

If you have to unlock your phone and/or open an app, it's not as easy to use. I'm just saying that Apple Pay is about as easy to use as it gets until you can just walk out the door of the shop without going near a checkout, the shoplifting detectors scanning all the items and charging you all via NFC.

Security

Two major security benefits of Apple Pay are Touch ID and abstraction of credit cards.

Touch ID means that nobody whose fingerprints aren't registered on that specific device can make a payment with Apple Pay. If your phone is stolen, the thief can't buy things with it as they could with a stolen credit card.

Abstracting the card from the payment is another huge deal. If you lose your credit or debit card, you have to cancel the card, which means that everything that gets paid automatically or that stores your card number for convenience will need to be notified of new card details. With Apple Pay, the card details are never transmitted. It generates a single-use payment token and sends that to the merchant, which then talks to Apple (instead of your bank) to get the EFT going.

This way, if the card is stolen, you can just add the new card to Apple Pay and keep paying for things like before. If the phone is stolen, the thief doesn't have access to your payment details.

Now, it's not impossible for someone to get into your phone if they've stolen it. A 4-digit passcode only has 10,000 possible permutations. Assuming 2 seconds per attempt, a thief could try all possible passcodes in an afternoon, but that would require ruthless dedication. It's likely that they wouldn't have to try all of them, though, since they'd stop once they reached yours, but it's also likely they wouldn't be averaging 2 seconds per attempt over a matter of hours.

Once they find your passcode, they can add their fingerprint to Touch ID, which would allow them access to your payments. But you can also quickly and easily disable Apple Pay on a device with the Find My iPhone feature. As long as you do this before they're able to get in — pretty frickin' likely unless you ignore your phone a lot — you're safe.

Actual usage numbers

Even though over half of my friends and family are using Android on Samsung phones, the image at the top of this post is the first time in the nearly two years since Samsung has had NFC payments that I've heard about it. None of them have ever mentioned it. This makes me wonder, have any of them ever used it?

How many Android users in general are using this feature?

When I lived in Australia, NFC payments were pretty common. My debit card was NFC-enabled for payments under $100. I just had to wave it over the payment terminal, collect my receipt and head out. No pin, no signature.

But considering that I've seen very few payment terminals in the US with NFC capability, I doubt a significant percentage of people with this capability on their phones have ever used it or even know it's there. My debit and credit cards are both swipe 'n' scribble — partying like it's 1989.

The reason Apple Pay is such a big deal isn't because the technology is finally being included in Apple phones; it's because Apple has finally convinced major retailers and fast-food restaurants to support it, as well. That's the kicker. The technology alone isn't enough. If Apple merely went the route that Samsung/Google went with their NFC-payments support and let the merchants adopt it at their own pace, it would probably be as useless for the next two years as it has for the previous two.

This has huge implications for Samsung/Google (whoever is responsible for the actual payment support in those phones), as well. In the same way that companies develop mobile apps for both Android and iOS, if they support Apple Pay, they'll likely add support for Android payments, too.

Better alternative to Rails' before_action to load objects

Aug 25, 2014 @ 07:30pm

Rails controllers have a set of callbacks called before_action and after_action (née before_filter and after_filter). They're pretty handy when you want to do something like this:

class AuthenticatedController < ApplicationController
  before_action :require_authentication

  def require_authentication
    # ...
  end
end

class UserProfilesController < AuthenticatedController
  def edit
     # ...
  end
end

In the AuthenticatedController above, we are telling Rails to run the require_authentication method before each action in that controller. Since the UserProfilesController inherits from it, it also inherits that callback.

One thing I see in a lot of code, though, is this:

class ProductsController < ApplicationController
  before_action :find_product, only: [:show, :edit, :update, :destroy]

  def find_product
    @product = Product.find(params[:id])
  end
end

A practice I've been following is never to modify the state of the controller in a callback. Whenever you do, the fact that @product (or whatever instance variable) is set can be surprising the first time you see it because your controller action didn't set it. In large controllers, this can be very difficult to find and if it's set in an inherited controller, it can be downright frustrating.

Another silly thing about using a callback to do this is that you are specifying which actions will be using this instance variable up front. The callback knows which actions are using the objects it loads. If you add a new method that needs that product, you have to add it to the callback list. This is a code smell; the controller itself has direct knowledge of what objects its actions use.

Also, it could be wrong, or at least outdated. For example, if you changed a particular action to load the object a different way than the way it does in the callback (say you want to eager-load some associated objects to avoid N+1 queries), but you forget to remove that action from the callback's list, you're querying the database at least twice for the same record:

class ProductsController < ApplicationController
  before_action :find_product, only: [:show, :edit, :update, :destroy]

  def show
    @product = Product.eager_load(promotions: :discounts).find(params[:id])
  end

  def find_product
    @product = Product.find(params[:id])
  end
end

This isn't necessarily a problem, but it's inefficient because you're querying the database and throwing away the result. It can cause problems, though, if you change how you query the database for that object, say by querying by a slug instead of an id. And then you have to look through the stack trace to try to find out what is firing that query that's broken, but it's a callback, so stack traces are meaningless.

But DRY!

It's important not to repeat the exact same line in every controller action that deals with a singular object:

class ProductsController < ApplicationController
  def show
    @product = Product.find(params[:id])
  end

  def edit
    @product = Product.find(params[:id])
  end

  def update
    @product = Product.find(params[:id])
    # ...
  end

  def destroy
    @product = Product.find(params[:id])
    # ...
  end
end

Here's what I do instead, and I've found it to work very well:

class ProductsController < ApplicationController
  def show
  end

  def edit
  end

  def update
    if product.update_attributes(params[:product])
      # ...
    end
  end

  def destroy
    product.destroy
  end

  private

  def product
    @product ||= Product.find(params[:id])
  end
  helper_method :product

  def new_product
    @new_product ||= Product.new(params[:product])
  end
  helper_method :new_product
end

Notice there is nothing in the show or edit actions, just as if we were using the callback, but we aren't specifying which methods require that object.

To achieve the best of both worlds, we're using memoization, which is just a fancy word for lazy loading. In order to load the Product into memory, we replace our use the @product instance variable with the @product method (as an aside, using accessor methods in your objects is almost always a good idea over using ivars directly).

Wait, there's already a gem for that

You may have seen this pattern before, but not done quite this way. This is almost exactly what the decent_exposure gem does for Rails controllers, but it gives you a handy DSL to do it:

class ProductsController < ApplicationController
  expose(:product) { Product.find(params[:id]) }
end

Turns out, that behavior is wicked-easy to implement:

class ApplicationController < ActionController::Base
  def self.expose(variable_name)
    define_method(variable_name) do
      @exposed_variables ||= {}
      @exposed_variables[variable_name] ||= yield
    end
    helper_method variable_name
  end
end

That is all it takes. Now you can have a nice DSL for these objects in your controller action or your view without adding yet another gem to your project.

It's up to you and/or your team whether you choose the DSL route or to use explicit methods like the first solution I showed. Either way is a much better solution than loading using a callback. In fact, just don't use callbacks. They're almost never what you want.

The Taboo of Salary Discussion

Jun 19, 2014 @ 11:49pm

The phrase "salary discussion" bring about weird feelings in me. My first thought is "salary negotiation", which always scares the hell out of me because:

  • Salary is considered personal and, therefore, something people don't really discuss with each other.
  • Because of that, I don't know how much a developer should expect to get paid.
  • As a candidate for a job, I don't want to ask for too much and the interviewer thinks "this guy has way too high an opinion of himself".
  • I don't want to ask for too little and the interviewer think "this guy cannot possibly be a professional developer".

The other thought that comes to mind is that, relating to the second bullet point above, in order to find out what other developers are getting paid, I have to ask them, which feels invasive. I don't know how anyone will take that question, so I'm always afraid to ask. I've always been told it's like asking how much someone weighs — it's personal.

The problem with that line of thinking is that, if you don't know what others in your field make at a similar level of experience, you don't know how much you should ask for.

I make $80k/year. I grew up pretty poor (single mother making barely over minimum wage), I struggled through college, even served in the military, so in a way that figure seems astronomical to me and it feels kind of weird to even think I deserve more.

Sometimes it doesn't matter …

I live with my roommate in a pretty cheap townhouse in the suburbs of Baltimore, MD (I didn't think it was all that cheap at first, but I'd lived a pretty minimalist lifestyle up until I moved here).

Since my expenses have been low, I haven't been really concerned with whether I've been getting paid as much as I should because I've made more than I need to get by. Worrying about that would've added stress that I just couldn't handle.

… but sometimes it does

I'm about to move into a new apartment in the city with my fiancée where the rent will be about $700/month more. Add to that the fact that I'll be going from splitting the expenses in a cheaper house with a roommate to being the only person with a paycheck in a more expensive place and my expenses/salary ratio just got a lot higher.

To clarify why I'm the only one with a paycheck there, my fiancée won't be able to get a job until she gets a US visa giving her residency, which probably won't be until after we're married.

Since suddenly money will be significantly tighter, I actually do need to know whether I should be getting paid more.

But I stiiiiiiill … haven't found … what I'm looking for

Before I got my current job, my entire career in programming had been freelance, so I have no idea how much money a full-time senior developer should make. So when thinking about this, I realized I didn't know how to approach researching it. I didn't think it'd be a great idea to bluntly ask my employer "Hey, am I being screwed here?" Though I imagine they'd probably be straight with me, even if I asked it like that, the idea of rocking the boat is really scary.

UPDATE: I want to clarify that I didn't mean "am I being screwed" seriously. I use a fair amount of hyperbole in my everyday speech, but I try to make it obvious and my usage of it here was not obvious. I know that my employers aren't intentionally short-changing me.

I asked my friend Alicia about it (she's an absolutely fantastic person if you ever get a chance to meet her). She told me she wasn't sure what a senior developer makes but that junior devs at her last job started at $70k/year.

That kinda stung a bit. A junior dev starts at $70k? My first reaction was: My more-than-a-decade of experience and my depth and breadth of knowledge of Ruby, Unix, and various front-end web technologies is only worth an extra 14%? But my first reactions are almost always pretty extreme and visceral.

So after I calmed down, I realized that maybe $80k was all they could offer at the time. I asked for $100k, but I was the first developer whose work they could bill for. Before they hired me, the only other employees were apprentices and they weren't billing clients for their work (quite commendable, since they acknowledged that it's unfair to charge full contract rates for inexperienced work). So the only money the company made was from billable time that the two of them (the business owners, not the apprentices) put in while also doing the business-development side of things. When I took that into consideration, it seemed a bit more reasonable. (UPDATE: They clarified for me that this was indeed the case.)

I had received offers from two other companies (one here in Baltimore, the other a remote position) and both were in the same ballpark, so I wondered if maybe the only jobs that were paying in the $100k range were in Silicon Valley making feline timesharing apps and you had to work 29 hours a day, 8 days a week. However, Alicia told me I should check payscale.com. When I answered their questions (location, experience, etc), this was what I saw:

Payscale.com results for a software developer in Baltimore

Well, shit. Now I'm really confused. After checking out the various graphs beneath that one, I confirmed that these numbers are for Ruby developers in Baltimore with experience similar to mine. So maybe I am getting paid 20% less than I should be?

Grab that cash with both hands and make a stash

So now I'm actually asking everyone out in the open. I'd like to know how much Ruby/Rails developers with a decade of experience are making in a full-time position. If you work in the industry, if you know someone who does, if you hooked up once with someone who does, I just want to know (well, not about the hookup, just the salary thing).

I don't want to know for the purpose of matching a person with a dollar amount. I'm more interested in finding out on a statistical level.

I'm also not asking because I'm looking for something better. I like my job. The people I work with are great. I'm curious because I'll likely be asking for a raise at my next review, and I'd like to have some numbers ready for that. However, if you're offering a significantly higher amount, you might be able to convince me. ;-)

Just as a closing thought: companies capitalize on the fact that people are afraid to talk about how much they make. It means that they can pay different people different salaries to work in the same position because they'll never know. It contributes to wage gaps based on gender and race. Help yourself and others in your position. Talk about it. By all means, tweet about it (I'll be monitoring the #DevSalary hashtag on Twitter or you can tweet directly at me).

My experience at RubyNation

Jun 07, 2014 @ 11:22pm

Yesterday and today, I attended the RubyNation conference in Silver Spring, Maryland. One of my goals this year was to attend more conferences because I've been trying to meet more people in the community. I attended BohConf last year in Baltimore and it was great, even though it didn't have a Ruby focus.

I suppose I'll get this bit of personal information out of the way because it's very relevant to almost the entire post: I suffer from generalized anxiety disorder. I go to great efforts to mask it because I don't want others to have to deal with it, but the idea of being around a lot of people, quite frankly, terrifies me. Thankfully, RubyNation is a small conference (only 250 attendees according to their website), so I figured it'd be a good place to start and asked if my company would buy a ticket for me. They ended up sponsoring the conference, so they shut down the office on Friday and we all went.

Day 1

I live about halfway between Baltimore and Silver Spring, so I drove down to the conference that morning. I mostly kept to myself or tried to stick with my work posse because being around people I know helps ease the anxiety.

The conference was really great. The presentations were fantastic. Sarah Allen gave a fantastic opening keynote, followed by Eileen Uchitelle talking about ActiveRecord's crazy association logic. A little bit after that, Davy Stevenson gave an awesome talk about the science, art, and craft of programming, which really hit home with me. It was pretty awesome to see three of the first four presentations being given by women.

Everyone was very friendly, but I still felt very nervous about talking to anyone, so I kinda sat and waited for people to approach me or tagged along with my workmates.

We broke for lunch around 1pm, which I'd been dying for because in the scramble to get ready to go I forgot to eat breakfast. My company took about 20 people to Nando's (by the way, excellent food, but overpriced for the quantity and level of service). We couldn't get a bunch of tables together so we broke into groups of 3-4 per table.

I got to sit with Florian Motlik and Russell Osborne. They're really awesome people and I really enjoyed talking with them. Russell actually reminds me a lot of Hampton Catlin, but with a beard. We took a #RubyFriends photo and everything. It was fantastic.

Spoiler alert: anxiety wins

After lunch, we went to a presentation about machine learning with Ruby. During the talk, the presenter mentioned the sexmachine gem, which claims to be able to tell whether a name is male or female. I'd heard of this gem before, so my first thought was "Oh, right, that gem that thinks I'm a woman".

When from the time I started preschool all the way up until my adult life, I heard "Jamie is a girl's name" a lot. A lot of bullies found it fun to torment me because I had the audacity to be given a "girl's name" at birth.

I tell you this solely because this was the presenter's very next slide:

http://i.imgur.com/yxg3Pzf.jpg

"jamie, female"

Notice that the name "Kim" is labeled as "mostly female", but it shows my name as unequivocally "female". Given that it took a lot of effort to manage my anxiety at the conference already, that's all it took to trigger an attack.

I gathered my things as calmly as I could and headed straight to my car. The day was over for me before 2:30pm.

Day 2

I laid in bed this morning wondering if I should even go back today. What if a similar thing happens? What if I'm just too afraid to talk to anyone? Then I'll have wasted all that time just so I could feel terrible about myself.

I think I felt guilty because my company paid for me to be there. Whatever the reason, I got out of bed, showered and went back. I actually managed a decent mood, too.

I'd talked to my fiancée and my roommate last night about my experience yesterday and they told me to remember to take breaks. I realized I hadn't taken any breaks away from the crowd yesterday, so today I did and it really, really helped. They both texted me to make sure I was okay, too. That's a nice feeling.

For lunch, I went to lunch with one of the guys from work and several other people I'd never met (including the aforementioned opening-keynote speaker, Sarah Allen) and we chatted about Ruby, JavaScript, Apple's new Swift programming language, Rails, and the US government — not necessarily in that order. Two out of two lunches at this conference went perfectly.

Nothing else super eventful happened for the rest of the conference. It was just a pleasant time all the way up until I left. Great talks, great people, hell they even served cheesecake! Okay, so one super eventful thing happened. :-)

Jamie at the Bat

The conference experience was totally worth it. I managed to meet some new friends despite my aversion to actually talking to people. I got beaned on my first at-bat, but I stepped back up to the plate and, though I didn't hit it out of the park, I did at least make it on base. I don't know why I went with a baseball metaphor, but I'm keepin' it.

The Seven Methods of Highly Introverted People

For other programmers who are introverted and/or suffer from social anxiety, I absolutely recommend going to a conference. A small one worked well for me. Maybe something like RailsConf or RubyConf would've been significantly more stressful, I'm not sure, but it's tough to imagine a small conference being worse for social anxiety than a large one.

I was lucky enough to have one so close to my house, but Katrina Owen told me in a Ruby Rogues Parley thread that one thing that helps her at conferences is to get a hotel close to the venue. This way, if you start to get overwhelmed, you have a place you can retreat to. I plan to do exactly this if I go to any conferences that are outside of my backyard.

There are almost certain to be moments you'll struggle with. Take breaks. Take breaks proactively and away from people. It's like dehydration: by the time you realize you're thirsty, you're already dehydrated. The later you realize you need a break, the longer break you'll need to calm down.

You'll likely need to be alone for a while afterward and that's okay. Ever since I got home, I've been in the basement avoiding everyone. It's how I unwind after being around people all day.

And now I'm exhausted, so I'm going to bed.

Rails idioms considered harmful

May 17, 2014 @ 08:17pm

I'm not sure if it's Rails itself or the community by which it is surrounded, but something encourages us to treat our Rails apps as if they are simply a web interface to the database. Consider the idiomatic Rails create controller action:

class ThingsController < ApplicationController
  def create
    @thing = Thing.new(params[:thing])

    if @thing.save
      redirect_to @thing, notice: 'Thing was saved.'
    else
      render :new
    end
  end
end

The good news is that, in a lot of cases, this is about all you need. If you're adding a product to your e-store's catalog, publishing an article, or any other time you're just giving the app some data to be presented later, it's perfectly reasonable to treat it as nothing more than an SQL INSERT statement wrapped in a web request.

The problem I see is when people essentially copy and paste this code (whether they actually copy/paste or rewrite it with little to no modification, the end result is the same) for absolutely every create action in their app. If, instead of a ThingsController, this were a UsersController, would you still treat it as a simple CRUD controller?

The reason I'm writing this is that, at work about a week ago, someone suggested I do just that, and it's been bothering me. At the domain level, "creating a user" tells me absolutely nothing. From the user's perspective, they're not creating a user; they are the user. They're creating an account or, put another way, registering.

License, registration, and proof of email address

I've tried renaming the User class to UserAccount or simply Account in the past and it feels awkward. What if other users can be added to the same Account for payment-consolidation purposes? How do you reference the user themselves if calling the registration process "creating a user account", which simply INSERTs a record into the user_accounts table?

First, I've stopped thinking of a lot of scenarios like this as simple CRUD. When a user registers with your app, you're not simply inserting a record into the database. After the user record is saved, you'll usually send a welcome email or an email asking the user to click a link to confirm their email address. Maybe you'll add them to a mailing list or create some default data for them.

Where would you put all of that logic? If you put it into the controller, then you have to duplicate it all any time you add a user outside the normal registration process. This could happen through the admin interface, in a Rails console, a user-invitation process, etc.

A lot of apps I've worked on put that logic in after_create callbacks on the model instead. When setting up associated models, this is definitely an advantage over putting it in the controller because whether you add the user through the normal registration process or through the admin interface, the default data will be setup with no duplication. Sounds great, right? It does until you realize that every time you test a persisted user model you're inserting, at a minimum, twice as many objects into the database as necessary. We maintain an app at work that performs over 10 inserts per user because it follows this pattern (it's okay, we didn't write it like that; it came to us that way).

I consider both of these approaches to be harmful and yet both are used in countless Rails apps that people pay actual money for.

Okay, rocket surgeon, where do I put this crap?

The way I've been dealing with user registrations — and several other processes that aren't basic CRUD — by instantiating what basically amounts to a fake ActiveRecord model. You talk to it somewhat like an ActiveRecord model, but it stores the data elsewhere.

class UserRegistration
  include ActiveModel::Validations

  attr_reader :user

  validates_presence_of :email
  validates_presence_of :password
  validate :passwords_match

  delegate :email, :password, :password_confirmation, to: :user

  def initialize(attributes={})
    @user = User.new(attributes)
  end

  def self.create(attributes={})
    new(attributes).save
  end

  def save
    ActiveRecord::Base.transaction do
      if valid? && user.save
        create_defaults
        UserRegistrationMailer.welcome(user).deliver
        return user # We don't want to return the result of the transaction call
      end
    end
  end

  def passwords_match
    unless user.password == user.password_confirmation
      errors[:base] << 'Passwords do not match'
    end
  end

  def create_defaults
    user.foos.create
    user.bars.create
  end
end

This way, if you use a UserRegistrationsController that uses the idiomatic Rails create action as shown at the top of the article, it will save the user just as you would normally, insert associated models, and send out the welcome email. This makes sure that inserting a user model is as lightweight as possible (the validations are in the registration, so are not run during testing) while still allowing you to insert user records (including fully registered users) easily from elsewhere in the app, such as a Rails console.

As a bonus, if you were including other information than just the user data, such as payment information, you could pass it to the UserRegistration and sort it out there.

class UserRegistration
  # ...

  attr_accessor :user, :credit_card

  def initialize(attributes={})
    @credit_card = CreditCard.new(attributes.slice(:card_number, :expiration_date, :cvv))
    @user = User.new(attributes.slice(:email, :password, :password_confirmation))
  end

  def save
    if valid? && user.save
      payment_gateway.add user
      payment_gateway.charge user, AMOUNT
    end
  end

  def payment_gateway
    @payment_gateway ||= PaymentGateway.new
  end
end

See how in the initialize method, we split out the attributes for the separate models. Without this object to wrap the two models, you'd have to use accepts_nested_attributes_for, which is poor form. Sure, there's a little extra code to maintain, but this isn't a bad thing. Since you're doing validations here, you don't need to do them on the User model. This lets you forget entirely about bypassing validations when adding the user from the admin interface and will increase the speed of any tests that hit the database.

TwitterGithubRss