Playing Minecraft when the Port is Blocked

I was at a conference this last weekend and the network blocked the port that minecraft needed to connect to the server. So I spent longer than I would like to admit setting up a ssh tunnel. Here's what I did:

1) Create the tunnel

ssh -L 8080:yourminecraftserver.club:25565 -p 22 -l yoursshuser -N yoursshserver.com

This will stay running in the terminal. Just leave it going while you play.

2) Configure minecraft to use that tunnel

Create a new server by selecting "Multiplayer -> Add Server" and use the following settings:

Server Name:
Proxy
Server Address:
localhost:8080

Now you should be able to connect and build that dirt hobble you've been planning.



How do you write great commit messages?

The best way to learn to write great commit messages is to go back and read them.

When reading code take a moment and go look at the git history every time you mutter "why did they do that." That's the point in time when you want to know the real "why" behind the change. If you don't already know how to to that, take moment to figure out a way quickly to access the history of a line in your editor or in your repo, the less friction the easier it is to go back and read about the changes.

If you make a habit out of this, you will quickly learn what is helpful and what is not. Then, if you are like me, you'll want to go back to slap your past-self for being lazy and giving a few bullet points of "what" was changed and not "why" it was changed.

Sound good? You in? Cool.

To get started just add the word "because" to your commits.

Lets look at an example.

Changed the post title font size

Changed 0.8em 16px.

h2 {
-  font-size: 0.8em;
+  font-size: 16px;
}

And what if I ever come across this file, I might wonder why this person strayed from the convention of using relative font sizes to pixels. I would would mutter "wtf" to myself and pop open the git blame in my editor for that line and read the commit message. This right here is the point that I want to know why.

Changed the post title font size

Fixed it to 16 pixels because when we increased the overall font size on
the blog the titles were wrapping on mobile views.

h2 {
-  font-size: 0.8em;
+  font-size: 16px;
}

Now this is helpful. It gives me context. I get clues on what changed in this code and what might break. And I can see that it wasn't some arbitrary change. Me in 6 months will appreciate this.

A commit already contains a diff, so it shows what was changed. No reason to write that up again. But nothing explains why you made that horrible hack or sweeping change.

Communicating the current reasoning to your future self is a super power.


Further Reading

There have been many posts about commit message from formatting to content. Here are a few of my favorite, should you want to level up:

Tim Pope's A Note About Git Commit Messages. This is formatting and syntax, but if you follow this I will be much, much happier.

Caleb Thompson's 5 Useful Tips For A Better Commit Message. A bit vim-centric, but great guidelines.

Stephen Ball's Deliberate Git. An in depth guide to commit messages. Worth the time to read and understand.

Keavy McMinn's How to write the perfect pull request. Slightly different than commit messages, but they really go well together.



Render a JBuilder template outside of a request

I like to use the built-in JBuilder for rendering JSON in my Rails apps. I particularly like that it is an actual view template, gives you the control and tools you need to easily build up the document. There is no need to teach your models about icky things like URLs and hostnames -- that can be rendered with view helpers as part of the request.

The one problem is there is no easy way to use those templates outside of a Rails response. But luckily Aaron came up with a helpful class to setup everything properly and mimic the Request. He even added support for setting things like the location header.

To use it in a service object (like say a rake task that runs on a worker process):

# Create the object
json_view = JsonView.new

# Set any headers that matter, where `posts` is the obligatory example resource.
location = json_view.location_url(posts)

# Render the template
payload = json_view.render(:show, posts: posts)

Pretty cool, eh?

His implmentation that takes care of all the details of the request:

class JsonView
  attr_reader :controller
  def initialize(env = {})
    @controller = API::V1::BeaconsController.new
    controller.request = ActionDispatch::Request.new(default_env.merge(env))
  end

  def render(view, **locals)
    controller.render_to_string(view, locals: locals)
  end

  def https?
    @_https ||= ENV.fetch("SERVER_HTTPS") {
      Rails.application.config.force_ssl
    }
  end

  def default_env
    {
      "SERVER_NAME"     => ENV.fetch("SERVER_NAME") {
        abort "Missing environment key: SERVER_NAME"
      },
      "SERVER_PORT"     => https? ? "443" : "80",
      "HTTPS"           => https? ? "on" : "off",
      "rack.url_scheme" => https? ? "https" : "http",
      "CONTENT_TYPE"   => "application/json",
      "HTTP_ACCEPT"    => "application/json",
    }
  end

  # Helpful shim reaching into the controller private stuff
  def location_url(beacons)
    controller.send(:location_url, beacons)
  end

  def respond_to_missing?(meth, include_all)
    controller.respond_to?(meth) || super
  end

  def method_missing(sym, *args, &block)
    if controller.respond_to?(sym)
      controller.send(sym, *args, &block)
    else
      super
    end
  end
end


Upload to imgur from applescript

A little scrip

on run {input, parameters}
  tell application "Finder"
    -- convert file paths to posix
    set imageList to {}
    set linkList to {}
    repeat with i from 1 to (count input)
      set end of imageList to POSIX path of (item i of input as alias)
      set file_name to name of (item i of input as alias)
    end repeat

    -- no images selected
    if (count imageList) is 0 then
      display dialog "No image files selected" with title "Imgur uploader" buttons {"Quit"} default button "Quit"
      return

    --upload
    else
      display notification "Preparing to upload " & (count imageList) & " images" with title "Uploaded Started"

      repeat with i from 1 to (count imageList)
        set apiKey to "26ff5c40cbedf50e7f81124ab473c1cc"
        set curlCommand to "curl -F \"key=" & apiKey & "\" -F \"image=@" & item i of imageList & "\" http://api.imgur.com/2/upload"
        set answer to do shell script curlCommand
        set atid to AppleScript's text item delimiters
        set AppleScript's text item delimiters to "<original>"
        set link to text item 2 of answer
        set AppleScript's text item delimiters to "<"
        set link to text item 1 of link
        set AppleScript's text item delimiters to atid
        set end of linkList to link
      end repeat
    end if
  end tell

  set links to joinList(linkList, " ")
  set the clipboard to links

  display notification "Successfully Uploaded Screenshot and Copied the URL to the Clipboard" with title "Uploaded Finished" sound name "Purr"

end run

to joinList(aList, delimiter)
  set retVal to ""
  set prevDelimiter to AppleScript's text item delimiters
  set AppleScript's text item delimiters to delimiter
  set retVal to aList as string
  set AppleScript's text item delimiters to prevDelimiter
  return retVal
end joinList


Versioning in the URL?

After showing my friend Guille the API I was working on he said:

guillec: whats with the versioning in the URL?
guillec: dont talk to me
guillec: ever again

I love hypermedia APIs, so why do I have a version in the URL? Aren't we supposed to version resources and not the entire API?

Well, I have my reasons.

But first, I do agree. This feels like a smell. If I see an API that does this I normally would make snarky comments. My gut tells me it is the result of poorly thought out API, a dated approach, or some other anti-pattern.

So, why do I put the version in the URL?

Because: It is hard to do things right.

So a little back story. A few constraints I have to work within. I am working at a little company on a small system that is being integrated by partners, often contractors or junior developers who just want to check it off a list and move on. So they want to crank out something with the minimum amount of work necessary.

Lets think about how they are going to use the API.

  • They will cut corners
  • They will hard code URIs
  • They will not set the headers properly
  • They will assume the media type
  • They will complain if the API is hard to use
  • They will complain if something breaks (no matter how many corners they have cut)

That's all compleatly fair. I want to make their job easier, and I don't want them to push back on integrating (lest an important deal fall through).

So now I think about what my goals are.

  • I want to make it easy to integrate
  • I would prefer if the code behind it was clean and maintainable
  • I want my API to appear to be well thought out and properly designed (For example if Guille was evaluating my service, I want him to be impressed)
  • I need to be able to change the API as our product evolves

A few constraints

I have been told by a few very smart and accomplished developers that the solution is to control the API and the client. But given my "little company/small system" I don't have the cycles to create and maintain Ruby, Node, PHP, Java and ColdFusion libraries -- and that's just the clients we have now. So it needs to be a common denominator, which is the HTTP API.

The same goes for media types. I know I can correctly report the media type I support throught content negotiation, but by the time I get that far I've lost most developers. Also to save time and money I am only supporting one media type. Just dont' have time to build out the others. Much less keep them all up to date. So effectively forcing a Hypermedia api into single media type. Not really ideal, but pragmatically what can be supported for now.

The compromise

Be as progressive as I can in the Hypermedia API. Pick a solid media type and stick to it. The point is to not reinvent new problems. HAL, JSON+collection, JSON API -- just pick one that works for you.

Expect the consumer to cut corners. Plan for hard coded URLs. Resource IDs and URLs to be stored in their system. Improper use of headers such as content type, accepts, even authentication.

My Approach

  • Handle the hardcoded URLs by versioning via the API
  • Force the content type to be JSON
  • Make it easy to Authorize
    • Authorization header (the documented and recomended way)
    • Session (logged in users can view the API in their browser)
    • Query Param (the It Just Works™ method, this way I email a url that will work for debugging or other support, but I don't publish this in the docs)

I hope I can find a middle ground that will make the 9-to-5er happy as well as appease the zealous hypermedia advocate.

Things would be differnent with different constraints. The API is not stable, things will need to change. I don't need many different representations of the resources. The clients consuming it will be the simpliset thing that works.

Are you using Hypermedia APIs in production and dealing with customers, zealots and unreasonable free loaders? I am curious how you handle this. Drop me a line or leave a comment.