Sun 05 December 2010
For the past few weeks, I've had the incredibly fun experience of living
in Tokyo, Japan. I've already fielded quite a few questions as to the
"why" I decided to do this, and in an effort to not re-type the story
another hundred times, I figured I'd throw it down here along with my
experiences thus far. This post is not programming centric; for those of
you who follow the feeds for them, you'll have something soon, no
worries.
The Backstory
Back in early November, I was at somewhat of a crossroads. I had
recently come to the conclusion that I'm not a huge fan of San
Francisco.
I went ahead and checked out Chicago after that experience, and while
it's an incredible city in its own right (and certainly one of my
favorite US cities), I found myself wanting more. The funny part about
traveling in the US is that for all its regions and supposed
differences, at the end of the day you'll find largely the same things
no matter where you go.
So I figured, alright, let's see what other countries have to offer. I
applied, and (somehow) got my passport within a week. The question then
became "where to?". I could've gone somewhere like England, France,
Germany... the standard "alright, let's backpack for a year and see the
world" destinations that are often suggested.
Thing is, I'm not like that. I enjoy jumping off the deep end; the way I
see it, if I can survive the biggest changes and come out fine, then
anything else in between is a cakewalk. This is largely one of the
reasons I chose Tokyo/Japan; not only is the language incredibly
different than anything I know at the moment*, but it is literally on
the other side of the planet.
(...though some would argue German is on the same level, if not
higher, but I digress...)
One of the exciting parts of this journey is the path I've taken. I flew
off the west coast, came to Japan, and will head to England and/or The
Netherlands for about a week after this. From there, I fly back to the
east coast. I will have fully circled the globe by the age of 23, under
my own power. This has been a goal of mine for quite some time now, and
it's really satisfying to see it come about.
Initial Life In Japan
The minute the plane touched down (after a lovely 12 hour flight) was
interesting, because the culture shock hit me immediately. Not
"uncomfortable, get me out of here" style, but definitely "wow, there is
definitely something different here". I'll state up front that this has
been evident the entire time I've been here, too; back home, I obviously
grew accustomed to a lot of things, and the way they're done here is
almost always radically different in some way. It definitely took some
getting used to, but overall I've enjoyed it so far.
I rented an apartment a little bit outside central Tokyo, in an area
known as Nishimagome. Trains into the central part from there are cheap,
and take about ~15 minutes, so overall it worked out incredibly well.
One part that I found very interesting was the feeling of being a
minority - while I'm sure this comes across as potentially ignorant to
some who'll read this, I've never actually felt that before in my life.
I've lived in areas as a kid where some might say I was, but there was
very little social divide in those scenarios. Being here incurred a
language barrier and a customs barrier (i.e, society here has their own
customs which the US doesn't necessarily follow), which sits on top of
the typical social divides that we as human beings tend to exhibit in
general.
For the first two weeks, almost nobody in Nishimagome wanted to deal
with me. It was very fascinating; some appeared to do it out of a lack
of understanding in regards to my home culture (and believing that I
didn't understand theirs), whereas others seem steeped in what some have
described to me as the "old Japan" ways. It's very evident the way
foreigners are treated differently here; while I had read about it prior
to arrival, I wasn't quite sure what to expect. Getting over that
initial barrier in the area I was staying in required a lot of careful
conversations, as if walking on a field of landmines. At the time of
this writing (about 3 weeks in), this has largely disappeared, but it
definitely took some effort - a very eye opening experience indeed.
Cleanliness Is Godliness
The streets of this country are incredibly clean. To be completely
blunt, living here for a stint has made me feel like shit as an
American. Tokyo is an insanely huge city, and the amount of trash on the
ground pales in comparison to that of New York City (NYC) or San
Francisco (SF). I believe that a large part of the reasoning behind this
is that you are literally looked down upon if you litter - in America,
we're far too accepting of waste and littering.
The ironic part is that it's nigh impossible to find a trash can half
the time here. Your best bet is to, hey, recycle everything at the bins
you'll find around vending machines and food marts. On top of this,
having this mentality around you the entire time brings a sense of
wanting things to be clean to you. I'll say what a lot of Americans will
deny out of pride: much of the time, in the US, I feel as though it's
perfectly fine to litter because everyone else is doing it. Here, I
can't bring myself to do it; the gravity of the act is taken to such a
higher level here.
Say what you will about peer pressure and such; none of it will matter,
because you'd be arguing the wrong point here. That scenario exists for
many Americans, and trying to solve things through peer pressure
dissolution efforts will go nowhere. Small scale deployments of the
Japanese recycling system in the US could potentially work, provided
people help to enforce and spread the effort around - I believe that
many recycling efforts in the US largely fail because people are given
the alternative. Having one right choice doesn't make you a communist,
people, it just means it's the best fit for the task.
Convenience Is Underrated
I've spent a decent amount of time in just about every American city,
and I can say with a relative amount of certainty that Tokyo easily
beats them all out when it comes to convenience. As I type this, it's 3
in the morning, and I have no less than 4 different shops open and 20
different vending machines within a one mile radius, all giving me
access to coffee, food, emergency supplies, and whatever else I need.
NYC comes closest in this regard, but Tokyo's ability to provide at all
hours is staggering, and still surpasses anything I've seen in NYC.
Cover Charges At Bars Are Annoying
Drinking in Tokyo can be quite an expensive task if you're not careful.
Most bars and clubs you'll hit up require a cover charge (anywhere from
$8 - $30, in my experiences), and if you're lucky that includes a free
drink up front. While I don't particularly care about this, it
inadvertently becomes a social barrier when out with a group - some
people aren't always game to pay for two drinks when they're only
getting one. In the US, the ability to just stroll into a bar and have a
drink with a friend is a nice luxury when compared with here.
Public Transportation Rocks, But Should Stay Open Later
I find public transportation here to be a catch-22 of hilarious
proportions. The ability to get just about anywhere in the entire
country by public transportation is incredible. This has nothing to do
with the overall size of the country, it's simply a situation where
they've paid attention and built the necessary infrastructure. If
trains were open past midnight, I'd call it a perfect situation, but
having to choose to stay in central Tokyo or run to catch a train home
around midnight can be quite the bummer if you're having a blast.
What's Next?
This is the first entry in a multi-part series, as I couldn't hope to
cover everything I've experienced in the past few weeks in one post. In
another week, I head to Europe for a stint, and then back into the US.
Traveling is an incredible experience, and I'll continue to do this as
long as it benefits me and helps me grow as a person.
Keep an eye out for the next entry in this series!
Tue 02 November 2010
I don't pretend to be a huge fan of Ruby. That said, I can respect when
a language has a feature that's pretty damn neat and useful. For the
uninformed, method_missing
in Ruby is something like the following:
# Basic class, no methods, but method_missing love
class Rapture
def initialize
@missing_msg = "Oh god, calling method_missing"
end
# Called when a non-existent method call on an instance
# of this class is made.
def method_missing(method_name, *args, &block)
puts @missing_msg
end
end
bioshock = Rapture.new
bioshock.play
# play doesn't exist, so this will output
# "Oh god, calling method_missing"
Obviously, this is a trick that should be used with caution. It can make
for some unmaintainable code, as a class with many methods could get
difficult to trace through and figure out just what the hell is
happening. It can be put to good use, though - take an API wrapper, for
instance. What's it consist of? Generally, nothing more than the same
function calls made over and over to various service endpoints.
Cool, let's use this in Python!
I recently rewrote Twython
to support OAuth authentication with Twitter (as of Twython 1.3). It
ships with an example Django application to get people up and running
quickly, and the adoption has been pretty awesome so far.
The funny thing about the Twython 1.3.0 release is that it was largely a
rewrite of the entire library. It had become somewhat unwieldy, some odd
two thousand lines of code with each API endpoint getting its own method
definition. The only differing aspect of these calls is the endpoint URL
itself. This is a perfect case for a method_missing
setup - let's
catch the calls to non-existent methods, and grab them out of a
dictionary mapping to every endpoint.
method_dictionary = {
"getPublicTimeline": {
"endpoint": "http://...",
},
}
class Twython(object):
def __init__(self, params):
"""
Store params and junk. Ordinarily more verbose.
"""
self.params = params
def __getattr__(self, method_name):
"""
This is called every time a class method or property
is checked and/or called.
In here we'll return a new function to handle what we
want to do.
"""
def get(self, **kwargs):
# Make our API calls, return data, etc
if method_name in method_dictionary:
return get.__get__(self)
else:
# If the method isn't in our dictionary, act normal.
raise AttributeError, method_name
# Instantiate...
twitter = Twython()
# Call an arbitrary method.
twitter.getPublicTimeline()
The source above is fairly well commented, but feel free to ask in the
comments if you need further explanation. This resulted in a much more
maintainable version of Twython - for each function that's listed in a
hash table, we can now just take any named parameter and
url-encode/combine it. This makes Twython pretty API-change agnostic of
the entire Twitter API. Pretty awesome sauce, no?
Thu 14 October 2010
Before we get into this, I'll note that this post is actually about
mobile web development, not the romantic adventures of anyone in
particular. You've been forewarned.
Sometimes in life, you feel as though doing things the "ordinary" way
just doesn't cut it. I've found this to be a common theme in my work,
and I'm not the only one who operates this way. One example is my
brother (one of them, at least). I recently dropped by my parents house
for a visit as I plan my next trip, and I was catching up with him as we
walked up to a store. We somehow ended up discussing his upcoming
Homecoming dance, and how there's some girl that he wanted to ask, but
in doing so go above and beyond the normal methods.
I sat there and sarcastically threw ideas at him for about 5 minutes, as
I'm prone to do when I'm bored. One of them involved using a spare
iPhone I recently came into possession of to display some message to
her. He decided to take it one step further, and asked me if I could
help him craft a simple game that, upon winning, would ask her to the
dance.
I found myself thinking the idea was pretty awesome. To make that long
story short, we built it, she liked it, he's happy, I'm awesome, and the
world keeps on a-spinnin'. The game can be found at the following link -
best viewed on an iPhone, but should still be beautifully awesome on any
device (Android, PC, WebOS, etc):
Give the game a whirl
Oh hallo thar Mobile Safari
So, making the game was an interesting experience. I opted to build it
in a Webkit wrapper - HTML/CSS/Javascript are a much faster way to
prototype, and I wasn't looking to spend 12 hours on this project (I
somewhat did, but not for the reasons one would think offhand). The
process we took was pretty simple - sat down, sketched out the game play
and general UI, then started building; I, of course, actually
implementing things in the tech sense, and my brother handling the
artwork/color scheme/etc. Building the game, all said and done, took us
around an hour and a half from start to finish.
At this point, I figured, let's Phonegap it
up and call it a day. This would've worked, except for the fact that
Apple has apparently blocked newer i(Phone|OS) SDKs from running on
Leopard. I've since upgraded to Snow Leopard, but seriously, this seems
a bit overbearing to me.
Of course, at that point, I wasn't going to upgrade my OS then and
there, as it was past midnight. I experimented with reverting the
firmware back to the 2.x series, which I'm able to build and target to,
but there were a myriad of problems there due (apparently) to some
earlier jailbreaking that had occurred with the device. Go figure.
As a last resort, I decided to bookmark the app on the phone to
"install" it. The one caveat with this approach is that it'd require an
internet connection upon opening it up every time. What'd be ideal is if
we could jam the entire thing into the Mobile Safari cache - there's a
simple trick here that'll make life easier. I found that Mobile Safari,
by default, won't cache sites like you think it would, but you can
supply it with an HTML5 Cache Manifest that'll be respected by the
browser, forcing everything to get shoved in the cache.
The cache isn't huge, though, and the initial load shouldn't be huge as
a principal. There are a lot of external scripts used here, mainly to
automate smooth CSS transitions so the device hardware accelerates
animations, so the entire app is roughly ~130kb. Small, in this case,
but the limitations were worth discussing.
To get around cold cache loads, the single image used in the game (the
strawberry) is Base64 encoded into the html file itself, and all scripts
are also placed inline. Combine this with a few Apache directives, and
it loads quick enough the first time. The final trick is the following:
# At the top of your file, specify the cache manifest (your_app.html)
<html manifest="dragonfruit.manifest">
# The cache manifest itself (dragonfruit.manifest)
CACHE MANIFEST
index.html
apple-touch-icon-precompressed.png
# Needs to be sent back to the browser as a header for the manifest (.htaccess, etc)
AddType text/cache-manifest .manifest
In there, we modify three files. In the app itself, specify the location
of the cache manifest; the second set is an example cache manifest you
can borrow (the icon is used in the bookmark flow for the iPhone); the
final piece is a header that needs to be sent downstream to the browser
when the manifest is requested.
Voila, we've installed an app onto the iPhone without compiling
anything. Shove it all into the cache, and it can sit there for quite
some time - if we were to combine it with some localStorage action, it's
an (almost) potent combination. It still doesn't beat the App Store for
distribution, but hey, it worked.
Wed 06 October 2010
It's been a good two months since I last updated this. Ordinarily I'd be
a little angry that I let it slide for that long, but in this case I
think it's warranted. For those interested, here's a summary of what
I've been up to, along with my thoughts on San Francisco in general.
Since leaving Webs.com (see my previous
post for more
information on that), I've been pretty much all over the United States.
About a week after leaving Webs, I embarked on an epic road trip with a
friend that went from North Carolina all the way to California. Driving
across the USA is a fun journey, one that I recommend everyone take at
some point. The midwest is a surprisingly desolate place; never before
have I seen so many sex shops randomly dotting the countryside.
Out of all the states that we passed through, a choice few gave me some
of the best memories. Louisville, Kentucky, was a fun stop, as I got to
finally meet up with my long time friend (from my old IRC days) Zach
Winter. We used to fight like brothers
back in the day, but he's become a pretty awesome web developer/designer
in the time I've known him, so between that and talking about old IRC
crap we probably wasted a good four hours there. Riverton, Wyoming was
pretty cool, as it's a totally small town in the middle of nowhere with
an indian casino. Driving through Yellowstone was something to behold,
and the same goes for the desert-esque areas. I could go on here, but
there's enough to write a small novel at this point.
California was an interesting time period, and is actually the primary
reason I'm even writing this post. I enjoy getting out and trying new
areas of the world, traveling and exploring is a truly exhilarating
experience that, in many regards, can't be matched. As is (seemingly)
the norm, being a developer, I naturally headed to San Francisco. The
city (and the "Valley" in general) are routinely hyped as being an
incredible experience if you're in the industry. Living there taught me
two things: I have a lot of reservations about the "startup" industry as
a whole, and San Francisco as an area to live in isn't all it's hyped
up to be.
I'm putting my reservations on hold for another post, as I'd like to
more carefully formulate those into something more concise to read. In
terms of the living area, though, I'll put it bluntly: San Francisco is
a trashy, over-hyped city that masquerades as a clean, eco-friendly
environment where there's a seemingly open exchange of new ideas every
day.
Before the inevitable shit storm starts here...
Let's pick apart that statement.
Walk down any street in the Mission, SOMA, or even North Beach, and look
at the amount of trash on the ground. Now, with a straight face, tell me
that San Francisco is a clean city - I'll bet money that you can't do
it. This is counter to a city like New York City (NYC); with NYC, it's a
trash fest, sure, but nobody is going to try and tell you that it's
actually a clean city. After living in the DC area for most of my life,
and checking out Chicago, Boston, and Seattle (all of which are fairly
clean in their nicer areas, which I'm comparing to the nicer areas of
San Francisco), I'd say the same sentiment goes for those cities.
I'll cede the point that this issue can go either way depending on who
you talk to, but my experience was that most people tried to claim it's
a clean city, and it quite frankly astounded me. Your mileage on this
one may vary, and I invite you to judge for yourself.
What follows is a dissection of some of the allures of San Francisco
living, at least from what I gathered through the various groups I hung
out with in my time there. We'll go one by one here. Feel free to grab a
snack if you're going to read any further, by the way.
The tech scene
This one could be construed as a personal preference, so I'll keep this
short. The tech scene in San Francisco bothers me much more than I ever
thought possible. Perhaps I just went to the Valley at a low point in
history, but seriously, what the hell is with the amount of startups
building on top of something like Twitter's API? Beyond that, how many
god damn social networks need to re-invent the fucking wheel before
someone finally wakes up and decides that enough is enough?
Hell, I can even deal with the existence of these things, but the fact
that you're taking funding for such concepts? You do realize there are
more important things in the world than blowing a couple hundred grand
on sharing pictures through Twitter, right?
There are a lot of cool ideas and new technologies being developed out
in San Francisco, but for every awesome idea, there's about four
ridiculous ones that are setting themselves up for failure by doing
something as stupid as relying on the API of a network that has a
history of letting people do all the discovery work for them, then
building their own version.
Tech companies (both good and bad) can exist anywhere, but it's a myth
that only great tech companies exist (and can exist) in San Francisco.
Live where you actually enjoy living and don't feel pressured to accept
and praise an area based on a set-forth notion that it's the
end-all-be-all of an industry.
The food scene
Huzzah, burritos. What's there to get for lunch? Oh... burritos. Oh,
wait, no, there's about three different French places all serving the
same stuff, too, so I suppose we could do that for lunch.
Past nine o'clock? Nevermind half those places if you want a quick bite,
they're either closed or going to be closing at that time. So your
options then become... oh, go into a bar, order a pizza, or get another
burrito. Such incredible choices in a city supposedly known for its food
choices - I definitely never had those choices anywhere else! Why would
I ever leave this place?
The people
I met a lot of awesome people in San Francisco, don't get me wrong.
Thing is, I've met a lot of awesome people in every city I've been to.
This is just part of society in general - no matter where you go,
there's people you like, and people you don't like.
With that in mind, let's take an objective look at San Francisco. 90% of
the people I met were transplants, and they all came for one of two
reasons: technology (the startup world specifically), or some artistic
venture that hasn't panned out and they heard that San Francisco is an
"accepting" city. This all ends up melding into a very "me too" culture,
where it's nothing but people clamoring for attention around their
newest idea.
This wouldn't even be that big of a deal if it wasn't compounded by the
fact that everyone essentially circle-jerks one another on these
concepts to a ridiculous degree. Yeah, you think you can form a real
business around something like a Firefox browser extension? Please take
a seat over there, your head has been in the clouds for far too long (no
pun intended).
Get to the point please
San Francisco feels incredibly fake, and gets a free pass due to the
overall net worth of the Valley. The city is an incredibly trashy place
to live, it has an incredibly overbearing "me too" culture, and almost
everything that's supposedly great about the city can easily be found in
other areas that are cleaner and provide a better overall living
experience.
It's funny, really. If you try to explain any of this to anyone living
San Francisco, there's a good chance you'll send them into a mode where
they feel the need to defend the aforementioned points. The only other
city I've found where people get that extreme is - surprise, surprise -
New York City. San Francisco is like the punk kid in school who, even
though they're really no different, felt the need to dress completely
different and act out to feel individual.
I suppose that's worked for people throughout history, though, so
there's not too much more to say on the matter. If you need me, though,
I'll be traveling around to cities that are a bit more pleasant and fun
overall (and, hey, if you enjoy living in San Francisco, more power to
you, but you just make me scratch my head).
Mon 02 August 2010
For those who haven't heard the news, my last day at
Webs.com was this past Thursday (July 29th,
2010). After three and a half years, I figured it was finally time to
move on.
It's interesting to reflect on such a large portion of a lifespan. When
I joined Webs (then Freewebs) back in 2007, I was actually homeless, and
was working a part time job at a Blockbuster. I had gotten pretty tired
of that routine, and started cold-emailing companies. Out of all of
them, Freewebs was the one who responded and invited me out to interview
with them.
I remember being shocked when, a few weeks later, I received an offer to
join up. Y'see, it's no secret that I'm pretty much self taught through
and through when it comes to web design - with no formal training, I was
surprised that anyone would consider me for a position in this field.
Accepting that offer led me down a long path that's definitely shaped a
lot of who I am today, both professionally and personally.
Prior to joining Webs, I knew HTML and CSS well, but when it came to
actual programming I had just dabbled here and there, never gaining a
solid understanding of the craft in general. Working at Webs was, in
many ways, a great substitution for a college experience. The amount of
things I learned is staggering - data analysis, in depth design
techniques, and more.
Granted, while all that certainly contributed to my growth, I worked my
ass off while I was there; I guess I'm simply stating that the
environment is easily one of the best possible places to ever work if
you're a developer. All those startup companies in San Francisco that
seem so great to work at? Good luck finding anything similar in the
Washington DC/Metro area... short of Webs.com.
So what's next?
I'm tired of Washington DC. It's a great city with a culture all its
own, but I've grown up around all of this, and I want to see more of the
world in general. The west coast is very appealing to me, so I'm most
likely headed out there. As my career situation develops, I'll update
this space accordingly.
Besides all of that, I've got my open source work to maintain, as well
as some other cool projects in the pipeline. This isn't the end, but
moreso the beginning of an epic awesome adventure.
I'm awesome.
Sun 18 July 2010
This is Old!
I wrote this when I was much younger, and arguably, a bit of a jackass (pardon my French). I keep it up for personal reasons, and there might be some technical content of note here... so just please ignore the tone.
Yeah, there, I said it - this is a stupid situation for a language to be
in. The concepts of Date
, Time
, and DateTime
are all pretty well related. Date
is a point in Time
, DateTime
is a really nice representation of
Date
and Time
mashed together.
In a world that actually makes sense, you'd be able to easily convert
between these types (e.g: DateTime
should be able to easily convert over
to a Time
object). Some people might suggest patching the aforementioned
classes (like Rails does, for parsing relative dates), but this just
feels like an incredibly hacky solution.
Now, normally, I'm not much of a Ruby guy, give me Javascript any day.
However, there are a lot of awesome projects written in Ruby, and it's
hard to deny that they've easily got the best packaging solution for any
language. As it so happens, earlier this week I was hacking on a little
Sinatra side project.
DataMapper was my ORM of choice here,
because it's just so beautifully plug and play.
In the example app we'll look at, it's your basic Post/Comment scenario.
For each Post/Comment, we want to be able to render the relative time
ago that the item in question was submitted (e.g, "16 hours ago", etc).
Rails has conventions for this baked in by default (because they,
y'know, enjoy polluting namespaces, go figure). When you're outside of
Rails and want to do this, it's somewhat more difficult.
Originally I started by storing the creation time as DateTime
; makes
sense, we should be able to convert this to Time
to do easy
comparisons against Time.now
, right?
Well, uhh, no. Definitely not that simple. After some digging around, I
discovered the dm-types
gem, which adds some extra types to
DataMapper. One of these types is known as EpochTime
, which is (you
guessed it) the time since Epoch that the entry was created.
With that, we can pretty much stay within the realm of Time
. Ripping
apart ActionView
gives us a good base to work with on the act of getting
a relative string; putting it all together, we get the following Sinatra
app (two files - the main Sinatra app, and our custom date_helper
library).
require 'rubygems'
require 'sinatra'
require 'dm-core'
require 'dm-migrations'
require 'dm-serializer'
require 'dm-types'
require 'date_helper'
DataMapper.setup(:default, {
:adapter => 'mysql',
:database => 'database_name',
:username => 'database_username',
:password => 'database_password',
:host => 'localhost'
})
class Post
include DataMapper::Resource
property :id, Serial
property :username, String
property :entry, Text
property :created_at, EpochTime
has n, :comments
end
class Comment
include DataMapper::Resource
property :id, Serial
property :username, String
property :entry, Text
property :created_at, EpochTime
belongs_to :post
end
DataMapper.finalize
DataMapper.auto_upgrade!
# Requests/views/etc
get '/' do
erb :index
end
post '/post/new' do
@post = Post.create(
:username => params[:username],
:entry => params[:entry],
:created_at => Time.now.to_i # See? Epoch-goodness.
)
if @post
# .create automatically saves the post; now override the created_at
# point before we pass back our JSON object to the view.
# "distance_of_time_in_words" is from date_helper.rb
@post.created_at = distance_of_time_in_words(@post[:created_at].to_i)
@post.to_json
else
{:error => true}.to_json
end
end
# Get views for comments, posts, etc
# Proudly (or shamefully, depending on how you look at it) ripped right out
# of ActionView and modified to base it all on the Epoch. Give credit where credit is due.
# from_time expects another judgement from Epoch (e.g, Time.whatever.to_i)
def distance_of_time_in_words(from_time, to_time = Time.now.to_i, include_seconds = false)
distance_in_minutes = (((to_time - from_time).abs)/60).round
distance_in_seconds = ((to_time - from_time).abs).round
case distance_in_minutes
when 0..1
return (distance_in_minutes==0) ? 'less than a minute ago' : '1 minute ago' unless include_seconds
case distance_in_seconds
when 0..5 then 'less than 5 seconds ago'
when 6..10 then 'less than 10 seconds ago'
when 11..20 then 'less than 20 seconds ago'
when 21..40 then 'half a minute ago'
when 41..59 then 'less than a minute ago'
else '1 minute ago'
end
when 2..45 then "#{distance_in_minutes} minutes ago"
when 46..90 then 'about 1 hour ago'
when 90..1440 then "about #{(distance_in_minutes / 60).round} hours ago"
when 1441..2880 then '1 day ago'
when 2881..43220 then "#{(distance_in_minutes / 1440).round} days ago"
when 43201..86400 then 'about 1 month ago'
when 86401..525960 then "#{(distance_in_minutes / 43200).round} months ago"
when 525961..1051920 then 'about 1 year ago'
else "over #{(distance_in_minutes / 525600).round} years ago"
end
end
Sun 18 July 2010
It's no secret that I primarily use this space to talk about programming
and the web at large. It's a huge part of who I am, but it's not all
that I am. Sometimes I see something so incredibly cool and inspiring
that I just feel the need to talk about it; such is the case with the
movie "Inception".
- Please note: the following is full of spoilers if you haven't seen
the movie yet!
- Believe me when I say that this is a movie that you should avoid
having spoiled at all costs, because it's just such an incredibly fun
ride. This post will also make little sense unless you've actually
seen the movie. Seriously, go see the movie if you haven't already,
then come on back, this post isn't going anywhere.
What really happened in this movie?
I'll start by making sure this is noted right off the bat: I believe
that the Wikipedia
explanation of
the ending of the movie is completely wrong. The article states that, in
the end of the movie, everyone wakes up on the plane just fine. The
genius part about this movie is that Christopher Nolan, the director,
rarely strayed towards one ending; everything throughout the movie is
meant to spark discussion about the final ending scene, where the top
may or may not have fallen.
Throughout the film, Nolan obviously took great care to make the
audience aware of the mathematics surrounding the way the levels relate
to one another. The idea with this is that, in the end, even though Cobb
is left underwater in the van, the time that he spent in the sublevels
beyond could be as little as a few minutes there, giving enough space
where he could've magically gotten back up through the levels.
That's all nothing but a ploy, though. Here's the thing - in the ending,
I believe Cobb never actually woke up. Let's look at the film this
way...
Cobb and his children
First off, the kids and the shot at the end. Did anybody else notice
anything strange about it? The kids never aged!. Cobb goes back to his
place and it's as if he never left. We're purposely never given a
timeline as to when Cobb and Mal had their little incident with Mal
having a bad case of PMS and jumping out a window. I'd say it's safe to
assume that this has to have been at least a few months to a year,
though; we're shown shots of Cobb talking to various psychiatrists,
attempting to persuade people that he did not, in fact, kill Mal. If
this is in relation to court proceedings of some kind... well, we all
know how long those acts can take.
That said, we really don't even need to consider that, it's just a nice
piece to note. What we should really be looking at is that, throughout
the film, every time Cobb sees his kids in a dream, they're the same
(just like in the end of the film). It's his last memory of his kids; in
some way, they're his inception.
Keep this in mind, because the rabbit hole goes a bit deeper.
Cobb and Saito: honoring the agreement
When the team is in the first sublevel, Saito takes a bullet to the
chest. There's a scene where he specifically states that no matter what
happens, he'll be sure to honor their agreement. Of course, at that
point in time, we all have reason to believe that Saito is going to make
it out alright, Cobb will be able to get back into the US, and everyone
will go on their merry way.
As the film continues, though, Saito's condition worsens, and he
eventually passes away in the third sublevel. This is a huge fact: Saito
is now in limbo. Cobb, after finally killing Mal, stays behind in
limbo to find Saito to make sure he honors the agreement.
See a pattern here? In this case, there's more than one way to honor
their agreement. Cobb eventually does find Saito, when Saito is much,
much older. They speak of honoring their agreement, which is why Cobb
came, and Saito reaches for the gun. This is the most notable piece of
their entire level of interaction throughout the movie - if dying in a
sublevel when you're that far under puts you in limbo, what happens when
you die in limbo?
Of course, we're never directly told. Tricky, tricky Nolan, but we'll
pin this down yet.
On Heaven, Hell, and Unicorns
Mal's dead, no? What's funny about Mal inside Cobb's subconscious is
that she's located in the basement of his mind, an eternal hell that
Cobb can't seem to get rid of, as if he was condemned to that fate for
his action against Mal (trying inception on her first). Eventually, when
they make it down to limbo, Cobb finally kills the idea of Mal - this is
his redemption.
Cobb is essentially painted as a fallen angel throughout the movie,
barred from heaven. By atoning for his sins, he's allowed back in and
everything is supposedly great. That said...
What was really Cobb's Heaven? Real life, where he got back to see his
kids? His one goal was to go home, to be with his family, but it's made
apparent to us, the viewers, that when you're in limbo it's difficult
(or almost impossible) to get out.
Bringing it all together
As I said before, Cobb never actually woke up. Saito reaching for the
gun is meant to imply that he kills Cobb, setting him free - not in the
sense of waking him up, but allowing Cobb to dream that which he's
wanted for ages, to be back with his family (hence why, when he goes
back to his kids, they're exactly the same as in every other shot).
Nolan again takes great care to make sure this is difficult to prove -
specifically, the scene where Cobb and Mal allow themselves to be run
over by a damn train. This is supposed to imply that simply dying in
limbo allows you to truly wake up. That said, unless Saito kills himself
and Cobb (which seems a little odd - Saito knew the rules of the game,
why wouldn't he just kill himself prior to Cobb finding him?), the final
scene really does seems like Cobb is dreaming forever.
See, Saito supposedly woke up just fine, made the call, everything's
great. However, what guarantee is there that either of them woke up
normally from limbo, the level that seriously messed up Mal? None.
This all brings us to the final scene with the spinning top: it was a
great move on Nolan's part to end it right as the thing supposedly
topples, essentially forcing the entire discussion this article was even
written about. Sure, we could assume that it signifies Cobb is alive and
well, not dreaming.
However, a friend of mine offered this suggestion, which I think really
ties it all together: she proposed that the top falling was Cobb giving
in to his dreams, accepting that reality as reality itself. This is
utterly genius, and makes an insane amount of sense.
The other theory that comes to mind is that it was Mal's totem
originally, and she's now, for all intents and purposes, finally gone, a
demon purged from his mind, allowing him to dream peacefully forever.
This movie was an incredible mental trip, and one I definitely intend to
watch again. What do you think? Feel free to leave comments below;
they'll be moderated to deal with spam and trolls, but healthy
discussion on this film is highly encouraged.
Tue 13 July 2010
I talk a lot about Javascript on this blog: client-side, server-side,
wherever the language can be used. It's not the only language I enjoy
working in, though; Python has always had a bit of a soft spot with me,
and with that comes some inevitable
Django love.
I use Django for a lot of my server side tasks where I don't feel I can
safely use something like Node.js. On top of
being battle tested beyond belief, it's a veritable bag of magic tricks
just waiting to be used. Take this one case I ran into recently: I'm
building a service (stealth at the moment, stay tuned) that has to do
something as simple as send out an email when a new user signs up.
Now, that email should ideally contain a few things. Let's assume that,
for a basic example, we're gonna just include their username, a brand
new password, and their full name (how we'll use each of these is shown
in depth below). Django makes sending mail pretty easy, using the
send_mail
function:
# Make sure you import this, otherwise... well, you get the idea.
from django.core.mail import send_mail
# send_mail is pretty straightforward, as you can see.
send_mail('Title', "Body", "from_addy", ["emails", "sent", "to"], fail_silently = True)
That's all well and good, but what if we want to do more than just a
simple string for our body message? Ideally, we should be able to treat
this like any other Django template. In practice, this is actually
incredibly easy (and fun).
The code should be fairly well documented, but for those who'd like a
little more verbose of a walkthrough, it's pretty simple: instead of
passing in a string, load up a template and pass it a rendering context.
See, what got me the first time around is that the render
method of
get_template
needs a Template Context to do the dirty work, not a
standard dict.
# We should all know what this is used for by now.
from django.core.mail import send_mail
# get_template is what we need for loading up the template for parsing.
from django.template.loader import get_template
# Templates in Django need a "Context" to parse with, so we'll borrow this.
# "Context"'s are really nothing more than a generic dict wrapped up in a
# neat little function call.
from django.template import Context
# Some generic stuff to parse with
username = "fry"
password = "password_yo"
full_name = "Philip J Fry"
# Our send_mail call revisited. This time, instead of passing
# a string for the body, we load up a template with get_template()
# and render it with a Context of the variables we want to make available
# to that template.
send_mail(
'Thanks for signing up!',
get_template('templates_path/email.html').render(
Context({
'username': username,
'password': password,
'full_name': full_name
})
),
'admin@moxlee.com',
['users_email@gmail.com'],
fail_silently = True
)
With that, here's an example of an email template - it's literally just
a Django template, but ready for all your email attributes.
Welcome {{ full_name }}!
Your username is {{ username }} and your password is {{ password }}.
- Management
Django's templating system is incredibly flexible, and can easily be
used for more than just your generic views. If you have any questions or
suggestions, feel free to throw them in the comments!
Thu 17 June 2010
If you're a developer working on a website that's getting any traffic,
you'll inevitably come up against the problem of making sure you're as
performant as possible on the front-end. You'll probably compress your
Javascript and CSS, maybe refine the slower portions of your site after
profiling them, and maybe (if you're smart) sprite your images.
You see, one of the chief goals in terms of a highly performant site is
to get the amount of HTTP requests as low as possible. Most people turn
to CSS sprites; they're a great technique for designers, and fairly easy
to understand. That said, they're not without their
downsides.
They can become quite an unmaintainable mess if you're not careful -
change the location of a few images, and you have to change the
corresponding CSS declaration to match it. On a large site, you'll end
up repeatedly putting together a puzzle that's wasting your time.
What if you're working on a team? How do you manage to keep one image
in sync across 2 people? 5 people? At this point, you're probably
wondering why I'm even bothering to rant on this, since these points are
all fairly well known. Well, here's the thing - there's an alternate
solution, depending on how open to the concept you are.
What the hell is Base64?
Just about every modern browser supports the concept of Data URI Schemes. With this,
you can do the following:
body {
background: transparent url(data:image/png;base64,
iVBORw0KGgoAAAANSUhEUgAAAAEAAABnCAIAAABO2r+ZAAAA
GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAA
AG9JREFUeNp8T9sNgDAIvJCu4Ay6rEO5hXEBP9yB0xLa0Fr9
aLgHBxTrdgpIASB8HoiAXf/VaJmSbbj1df1jnpyn1qfViF+e
31T3Rxw8yzSez4u4u89medWMtWiZB197jYP8t1dv878u85T2
47oFGAC4z6tdlRsLNAAAAABJRU5ErkJggg==) repeat-x top left;
}
A bit ugly? Yeah, you might say so. Effective? Definitely. The above
code simply generates a blue gradient that tiles perfectly. The really
long block of text you see there is a Base64 encoded string that
essentially gets transformed into your image. There's various different
ways to generate the Base64 representation you need; if you want a
really simple tool, check out this Firefox
extension.
The format of a Data URI is fairly simple to understand - in this case,
we're saying that this is a PNG, getting passed via Base64, and then the
Base64 string itself. If it helps, think of it as a glorified function
call.
As I noted above, most modern browsers support this technique. The one
caveat worth mentioning is that Internet Explorer 8 is limited on the
size of a Data URI to around 32kb. It's not really recommended to use
this technique for anything above that size, but hey, your life, do what
you want.
Oh, and Internet Explorer 6 and 7 have absolute zero support for this
method.
Don't fret, we can make Base64 encoding work in IE6/7!
Internet Explorer (Explorer in general, really) supports another file
type that does understand Base64: mhtml. We can use this trick to
make IE6/7 do some awesome magic:
/*
Content-Type: multipart/related; boundary="_"
--_
Content-Location:1
Content-Type: image/png
Content-Transfer-Encoding:base64
iVBORw0KGgoAAAANSUhEUgAAAAEAAABnCAIAAABO2r+ZAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAG9JREFUeNp8T9sNgDAIvJCu4Ay6rEO5hXEBP9yB0xLa0Fr9aLgHBxTrdgpIASB8HoiAXf/VaJmSbbj1df1jnpyn1qfViF+e31T3Rxw8yzSez4u4u89medWMtWiZB197jYP8t1dv878u85T247oFGAC4z6tdlRsLNAAAAABJRU5ErkJggg==
--_--
*/
body {
background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAABnCAIAAABO2r+ZAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAG9JREFUeNp8T9sNgDAIvJCu4Ay6rEO5hXEBP9yB0xLa0Fr9aLgHBxTrdgpIASB8HoiAXf/VaJmSbbj1df1jnpyn1qfViF+e31T3Rxw8yzSez4u4u89medWMtWiZB197jYP8t1dv878u85T247oFGAC4z6tdlRsLNAAAAABJRU5ErkJggg==) repeat-x top left;
*background: transparent url('mhtml:http://absolute_url.com/css_file.css!1') repeat-x top left;
}
What we're doing here is fairly simple, but hilariously hacky. Take a
look at the top of the file - it's a damn MIME header, with a little
"pointer" (content-location) to our Base64 representation. We then
just do a second background declaration for IE only that points to the
same stylesheet, but parses it as mhtml instead. Our !1 is simply
an identifier pointing to our first declaration - subsequent encodings
could use 2, 3, "jackalope", whatever you want. Each "block" is defined
by a "separator" or "boundary" - in this case, we're using "_".
I stumbled across this little trick while working on performance for
Webs.com. However, it seems I can't take credit
for it - Stoyan
Stefanov
posted on this awhile back. However, finding his work led me to one
barrier that I've yet to see a solution to.
IE7 on Windows Vista - oh god, why?
It would seem that, due to some of the security settings on Vista (and
maybe Windows 7), IE7 refuses to load the necessary
styles.
Stefanov advocates making the browser always request the mhtml as a
new file. This is counter to the goal, though - we want that file
cached.
Well, I happened to stumble on an easier solution (a combination of
reading the MHTML spec and rearranging formats out of madness). Just
make sure to end your IE hackery on a boundary declaration - the IE code
above already does this: notice the "--_--" right before the end of the
comment containing all the Base64 encodings for IE. This'll have IE7
parsing correctly everywhere, and we can all sleep soundly at night.
Whew! Awesome, now what?
Well, that's for you to decide. This technique can be quite useful - at
Webs.com, I was able to cut the size of our
sprite down immensely by relying on this trick for all the background
tiling gradients on the page. In my humble opinion, this trick is good,
but it works best when you combine it with a CSS sprite. I've found the
best method is to split the usage down the middle - constant, rarely
changing pieces become encoded, and the other pieces (testing-related,
generally) get sprited out.
With any luck, this post can help someone else out. It seems like
there's a lot of information regarding this technique, but it's been
haphazardly organized over time. This isn't quite a "definitive" guide,
but it aims to be a kickass outline!
Wed 09 June 2010
In my line of work, I edit a lot of legacy code, and with that I see a
lot of the following:
// Bad practice. Can you see why?
var foo = function() { alert("bar"); };
setTimeout("foo()", 2000);
That little piece of code is actually a really bad way of doing things,
and (to me) is illustrative of when someone is working in Javascript and
doesn't actually know what they're doing.
For those who don't know (and would like to learn), setTimeout
(and its
sister, setInterval
) can accept a string of code to be executed as an
argument. Know what other method takes a string of code and executes it?
eval()
does. Generally, methods like these should be avoided, as they
leave ways for arbitrary scripts to run if you're not careful.
So how could the above code be improved? Take the following:
var foo = function() { alert("bar"); };
// Better practice. Note how the function is passed this time.
setTimeout(foo, 2000);
What's important to remember here is that *everything* in Javascript
is an object. This may seem like grade school material, but it's
surprising how many people miss it - since our function (foo
) is an
object, we can point to it like any other object. What we're essentially
doing now is, instead of telling setTimeout
"hey, evaluate this script
after this timer expires", just "run this function when this timer
expires". There's no need to invoke eval()
for such a simple operation.
But what about my arguments?
Yes, you can still pass arguments with this form. Whereas before you'd
make up a whole string to be executed, you'd now just run it with an
anonymous function. For those of you using jQuery, this should feel very
familiar:
// Bad practice. Why concoct such an ugly string?
var delayedLol = function(laugh) {
setTimeout("alert('Laughing: " + laugh + "')", 2000);
};
delayedLol("bwahahaha");
// Instead, pass around your argument (laugh) with anonymous functions.
var delayedLol = function(laugh) {
setTimeout(function() {
alert('Laughing: ' + laugh);
}, 2000);
};
delayedLol("bwahahaha");
Javascript is incredibly flexible. If you're going to work in it, take
the time to actually understand what's going on. You (and your users)
will be better off for it.
Thu 13 May 2010
I had the awesome chance to give a presentation at the May 2010 meeting
of Refresh Fred. The talk I gave was on an
introduction to jQuery (as well as some basic Javascript).
The great part is that, since I opted to build the presentation in HTML,
CSS, and JS, it's easily viewable online. You can check out the
presentation
online, or check
out the source on
Github.
The entire presentation is MIT licensed (of course, that goes as far as
a presentation even so much as *can* be licensed). Feel free to take
the code, remix it, extend it, or re-use it - go crazy and enjoy.
Mon 10 May 2010
Alright, so while it's taken me a nine hour long sprint of coding and
design, I've finally revived Veno. This is pretty significant, at least
on a personal level - the last time I had a personal site and portfolio
online was around the beginning of 2007.
Several people have asked me why this took so long, though, and so I
figured I'd take a moment to jot down my thoughts on the matter.
Full time jobs take... well, time
See, the biggest draw on my time over the past 3 years has been my
day job with Webs.com. I wanted to take the time
to really dig in and better my skills in this craft, and there's really
been no better opportunity presented to me since. It's been grueling at
points (week long coding sessions without sleep to push a redesign out
the door, anyone?), but well worth it.
Now, after three years, I've found that I missed having a personal
platform to do... well, anything I wanted to, in terms of the internet.
This led to a six month period of trashed redesign attempts for Veno;
after enough failed designs, I decided to just power through it in a
day, and this is the result. It's heavily CSS3-based, but should fall
back gracefully in just about every browser. I foresee myself refining
it over time, though - there's certain things I'm unhappy with, such as
the overall "tightness" of the layout. Expect to see it open up and
breathe a bit more over the next few weeks, as well as become more
personalized.
Ah, the micro-blogging phenomenon known as
Twitter. For a pretty long while, Twitter
dominated most of my "soapbox" needs. I could throw out a small note
about whatever I'm feeling, and it would instantly hit an incredibly
connected and thriving community. I've probably met and interfaced with
more developers and designers over Twitter than anywhere else!
Of course, Twitter is limited to 140 characters. What if I wanna throw
up a Javascript or Python tutorial? That certainly can't be done over
Twitter (at least, not without annoying the hell out of everyone). By
re-igniting Veno, I can provide some much needed separation to my "web
2.0 social aspects", so to speak. Expect this space to be occupied by
deeper thoughts and more intricate material, whereas my Twitter feed
will remain filled with smaller pieces (updates to my open source
projects, etc).
So there it is, all laid out. It's taken a few years, but I firmly
believe that this is a case of "good things come to those who wait".
It's good to be back - expect to see some awesome things here in the
next few months!
Mon 25 January 2010
This is Old!
I wrote this at a much younger age, when I was honestly a bit of a jackass (pardon my french). I'm leaving it up because this is my personal space, and I periodically review my old work to see how far I've come. You probably shouldn't take too much away from this piece, though.
Interviewing people can be one of the most aggravating things in this
industry. Just about everybody who walks through your door could be some
run of the mill engineer who's set in their ways.
Now, I should be fair here - I probably see this more often, due to the
position I'm in. As a front-end developer, I can't begin to count the
number of times I've had somebody come in for an interview, expecting
their database skills and server-setup capabilities to translate into
web skills. It's maddening, at points, and a real problem in the
industry - we're only now beginning to get out of the era where
front-end development is treated as a necessary evil.
Front-end development carries its own unique set of problems. Nobody
who's been doing database optimizations for the past five years is going
to be able to hit the ground running on UI work; the playing field for
this stuff is constantly changing. To that end, I've started trying to
come up with different interview questions that can help show how
someone attacks the kind of work we routinely face.
Seeing as how I've been in Javascript-land for the past four months, the
most recent one I came up with is this:
var t = {
r: {},
b: function() {
var m = "%45%6D%61%69%6C%20";
for(var i = 0; i < arguments.length; i++) {
if(arguments[i] instanceof Array) t.r.a = arguments[i];
else t.r.f = arguments[i];
}
for(p in t.r.a) {
if(t.r.a[p] === decodeURIComponent("%72%65%64%64%69%74"))
m += "%72%79%61%6E%40%76%65%6E%6F" +
"%64%65%73%69%67%6E%73%2E%6E" +
"%65%74%20%74%6F%20%74%61%6C" +
"%6B%20%66%75%72%74%68%65%72";
}
if(typeof t.r.f === "function") t.r.f(m);
}
};
The problem is simple: figure out what arguments need to be passed to
t.b()
for it to display the proper message.
I feel like this is a great problem to have someone solve, as it
illustrates a few things right off the bat. Are they scared away by
encoded characters? Do they even know how to decode those characters?
Can they tell, based off the arguments work being done, what types of
objects need to be passed?
It helps to draw a clear line between someone who just manages to get by
with Javascript, and someone who can really dive in and tear things
apart if need be. The code is just ugly enough to make some people roll
their eyes back into their head, but it's deceivingly simple when you
get down to it, and that's why it succeeds at the job.