I notified my employees and clients this week that itsbspoke will cease operations on May 31, with the month of May serving as a transition and severance period for the team. I am now looking for full-time employment starting June 1.
I feel such gratitude that I’ve had an opportunity to work with wonderful teammates and clients during the past five years. I knew there were significant entrepreneurial risks as I grew my team and expanded the scope of itsbspoke. Unfortunately, the opportunities I envisioned as a business owner did not materialize.
I am proud of what we have accomplished with our clients, with Charlotte’s startup community, and through the civic projects we’ve undertaken to benefit the City itself. PitchBreakfast and Charlotte Startup Weekend are now fixtures in the entrepreneurial community. Code for Charlotte is now improving quality of life for all Charlotteans. CRTEC and it-ology contribute significantly to the technology community here. I’ve made so many new friends through my newsletter, and heard from so many that it has made a difference for them, as well.
I may return to these commitments in time, but now I’m eager to open a new chapter in my professional life, a chapter with more focused personal aspirations and a greater dedication to fulfulling the growing needs of my young family.
What’s next for me:
I am looking for full-time employment with a target first day of June 1. I am committed to staying in Charlotte. My ideal position would allow me to achieve the following goals:
Work toward a more just world
I believe in the possibilities of a world of with abundant economic opportunity and justice. I’ve loved getting involved in the civic technology community her in Charlotte. The opportunity to make a difference in my community, and other communities, through the power of technology is important to me.
Develop myself as a manager and leader
My next step is not becoming 10x more effective as a software engineer, but in creating and leading teams that can reach new heights and accomplish what was once thought impossible. I might not have an MBA, but I’ve led teams down the road of hard knocks, built the relationships necessary and achieved success more often than not. This represents the next phase for me.
Ditch the headphones
I no longer feel the need to prove I can slap on the headphones and crush code to make a delivery date. I’m certainly not opposed to bringing my whole self to any assignment, and of course that capability is valuable.
I spent the first twenty years of my career learning all I could about how to deliver and operate successful web applications that scaled. While that experience certainly helps avoid expensive mistakes and failures, I’ve learned that technology alone is never ultimately responsible for a project’s success. My opportunities for growth involve attending to the business, organizational, and leadership dimensions of succes, and that requires setting the headphones aside.
Get in touch
With these goals in mind, if you think you or your firm might be a good fit for me, or if you know of someone I should speak with about possible opportunities, let me know via email or LinkedIn
As we’ve discussed at certain points in the past, user experience is extremely
important, and back-end developers have a lot to do with that as well. Many
users can deal with ‘ugly’ if the interface is clear, but no one on Earth likes
slow! We’ll look at how to take needed work out of the request/response cycle
in this exercise.
Step 0
We’ll be revisiting the house project with
this exercise. I’ve merged the work that we’ve accomplished into master, so
that you’ll be able to either update your forks, or pull the changes down
locally.
What’s that, you weren’t working on a branch when you made your changes, and you
can’t apply my changes quickly?
If you have made changes on master that are now irrelevant, try issuing these
commands:
Terminal
1234
git commit -a -m "Saving my work, just in case"git checkout -b save-my-work
git branch -D master
git checkout -b master -t origin/master
That should get you ready to work again. But create branches when you start
working! It’s easy! Here’s the branch I’d start here:
Terminal
1
git checkout -b friend-graph-sidekiq
Step 1
Add these files to your Gemfile:
Gemfile
12345
gem"koala","~> 1.8.0rc1"gem'sidekiq'# add this in the test groupgem'mocha',:require=>'mocha/api'
Install them. You should know how by now! Ask a neighbor if you don’t.
Step 2
Put these contents in spec/models/social_connection_spec.rb
require'spec_helper'describeSocialConnectiondodescribe"validation"dosubject{build(:social_connection)}it{shouldbe_valid}it"should require a user"dobuild(:social_connection,user:nil).should_notbe_validendit"should require a provider"dobuild(:social_connection,provider:nil).should_notbe_validendit"should require a uid"dobuild(:social_connection,uid:nil).should_notbe_validendenddescribe"associations"doit"should be present on user"dobuild(:user).respond_to?(:social_connections).should==trueendenddescribe"Facebook"dolet(:user){create(:user)}describe"interface"dosubject{FacebookInterface.for(user)}it{should_notbe_nil}it{shouldbe_a(FacebookInterface::StubInterface)}enddescribe"usage"dolet(:fbi){FacebookInterface.for(user)}endendend
This will give you a spec to pass! Run your specs with either:
Terminal
1
bundle exec guard start -i
or
Terminal
1
bundle exec rake spec
if you know that guard isn’t working for you.
To pass this test, you’ll need to:
create a model with the right fields and types
add the proper associations throughout the domain
add validations to the class you create
If you’d like a hint, download this file into
spec/factories/social_connections.rb, or simply refer to it inline.
Our goal with this step is to create a record that allows us to keep track of
some basic information for social connections on the part of our users. When
you have this spec passing, you have the domain layer ready! Now let’s proceed
to the integration.
Step 3
Place this file in spec/support/facebook_interface.rb.
require'spec_helper'describeFacebookFriendWorkerdosubject{FacebookFriendWorker.new}it"should include the line 'include Sidekiq::Worker'"dosubject.respond_to?(:jid).should==trueendcontext"when processing friends"dobefore(:each)do@user=create(:user)endit"should save all friends"dolambda{subject.perform(@user.id)}.shouldchange(SocialConnection,:count).by(6)endcontext"attribute saving"dobefore(:each)dosubject.perform(@user.id)@friend=SocialConnection.where(uid:"1905046").firstendit"should store uid"do@friend.should_notbe_nilendit"should save provider"do@friend.provider.should=="facebook"endit"should store name"do@friend.name.should=="Joel Bonasera"endit"should be bidirectional"do@friend.follower.should==true@friend.follows.should==trueendendendend
This will give you the next spec to run. This will test that you can progress
through the Facebook API response, and save the results to the DB in the
appropriate manner.
It’s customary to create an app/workers directory to place your
FacebookFriendWorker, as well as any other background workers that
you create. So the code that you write to pass this test should go in
app/workers/facebook_friend_worker.rb.
When your specs are passing here, we’ve added the ability to defer work outside
of the request/response cycle. We’re most of the way to seeing this work!
Step 4
Add this spec to your spec/models/authentication_spec.rb file:
spec/models/authentication_spec.rb
123456
context"saving Facebook auths"dosubject{build(:authentication)}it"should enqueue a Facebook friend saver when saved"doexpect{subject.save}.tochange(FacebookFriendWorker.jobs,:size).by(1)endend
Write a lifecycle method on Authentication that will enqueue the worker. We’re
definitely getting close now!
Step 5: Putting it all together
Code wise, you are ready to go! We have a few more things to put in place
before we can actually run the code and have everything work.
First, sidekiq requires redis, so let’s install that.
Terminal
1
brew install redis
We don’t want redis to run all the time— it’s not as cool as postgres. It does
need some configuration to run, so let’s save this file at
config/redis.conf
I had to copy and paste in information from a variety of sources to end up
with something I liked at the time of this writing. Since I want to walk my
students in Launchpad Code
Academy through this process, I figured I’d make this walkthrough public.
It may help newcomers for quite some time to come!
About this solution
We are going to be using a server-side OAuth authorization. The mechanism
uses some JavaScript checks and interfaces with the JS Facebook API, but
ultimately the connection is made on the server-side.
You don’t necessarily have to be using Devise, but if you’re not, our tips
about how to leverage this approach for Facebook login may not be helpful.
With a little extra work, you can allow users that have attached their
Facebook account to log in with Facebook. You might even be able to adapt this
approach to allowing users to create accounts with a single click. But you
won’t like that as much when you want to get Twitter involved, since Twitter
doesn’t send an email address in its OAuth callback. It’s best to have existing
users affiliate their accounts and then providing login as a convenience.
Getting started
Step 1: Installing gems
Include these gems in your Gemfile:
Gemfile
12
gem"omniauth"gem'omniauth-facebook','1.4.0'
Install them in your terminal with the bundle command:
The config/initializers directory is designed for use on Rails startup to
configure how libraries are intended to operate. In this case, we want our
Rails application to know that we are using Omniauth, and are configuring the
Facebook provider to reference environment variables to run.
To set these environment variables properly, we’ll need to go get some info
from Facebook.
Creating and configuring a Facbook App
Step 1: An app
I honestly don’t remember what it’s like to register for a Facebook developer
account, other than it should be free, and it should happen at the
Facebook Developers site.
When you’ve registered properly, there should be an “Apps” tab in your
navigation. Click on that to travel to
your list of apps.
Click “Create New App”. You should pick a name that indicates you are doing
testing. You can place it in a namespace, if you like, but that’s optional.
Mine looked like this
Click “Continue”, and you should be brought to an application screen that
contains your App ID (or API Key) and your App Secret. Note those, but we’ll
need to fill in some information here.
In the “App Domains” box, put ‘localhost’
Click the green check on “Website with Facebook Login”, and fill that in with
http://localhost:5000/. My students (or anyone who uses my Rails templates)
will be able to use this. This value may be different for you— make sure that it
matches whatever you use in development. localhost:3000 would be common if you
are using rails s and appname.dev would be likely if you were using
Pow.
Mine looked like this
Step 2: Installing application details
Students in my class use foreman to run their development
environment. If you won’t, perhaps you can consider dotenv,
to load env variables from files for you? It’s important not to commit
sensitive information like this Facebook App Secret to your repository. Note
the difficulties and caveats, should you ever need to remove sensitive data.
Usage of foreman or dotenv can help with that.
If you are using foreman, you can add these files to your .env file (which is
not in version control). Instead of the values below, they should match your
own app’s key and secret that you obtained previously. You cannot just copy and
paste this file. I totally made up these numbers, and they will not work.
Step 1: Create a model to store the authentications
We don’t want to tie authentications to a user in a 1-1 way, since we’d love
to allow connecting with other social networks by default. We want a user to
have many social networks attached, potentially, so we’ll create a model that
appropriately attaches to users.
Create an Authentication model using this command:
Terminal
1
bundle exec rails g model Authentication user_id:integer provider:string uid:string name:string oauth_token:string oauth_expires_at:datetime
This will create a migration for you similar to this:
You’ll also need to provide a mechanism for Omniauth to save the data it can
provide to your DB for your use. After you issue the above command, you should
have an app/models/authentications.rb file. Replace that file with
these contents:
Be sure to also add has_many :authentications to your
app/models/user.rb file. And don’t forget to run your database
migrations here!
Step 2: Create the authentication user interface
Terminal
1
bundle exec rails g controller authentications index
This will create an authentications controller, and a view file for you. We
don’t quite want any of what we get out of the package. Copy these file
contents into your authentications controller:
Place this file into your JavaScript directory. Note that this one won’t
work either by just copying and pasting! You need to include your non-sensitive
App ID :
// Additional JS functions herewindow.fbAsyncInit=function(){FB.init({appId:686338067928534,// App IDstatus:true,// check login statuscookie:true,// enable cookies to allow the server to access the sessionxfbml:true// parse XFBML});};// Load the SDK Asynchronously(function(d){varjs,id='facebook-jssdk',ref=d.getElementsByTagName('script')[0];if(d.getElementById(id)){return;}js=d.createElement('script');js.id=id;js.async=true;js.src="//connect.facebook.net/en_US/all.js";ref.parentNode.insertBefore(js,ref);}(document));functionfblogin(){FB.getLoginStatus(function(response){if(response.status=="connected"){location.href='/auth/facebook/callback?'+$.param({signed_request:response.authResponse.signedRequest})}else{FB.login(function(response){if(response.authResponse){'/auth/facebook/callback?'+$.param({signed_request:response.authResponse.signedRequest})}})}})};
Copy this view file into place, as the bulk of our tutorial actions will
happen there. There are HTML comment blocks below— my blog assumes I want a
hyphen, when I really do want two dashes. Be sure the file matches this gist.
<%if@authentications%><%unless@authentications.empty?%> <p><strong>You can sign in to this account using:</strong></p> <div class="authentications"><%forauthenticationin@authentications%> <div class="authentication"><%=image_tag"#{authentication.provider}_32.png",:size=>"32x32"%> <div class="provider"><%=authentication.provider.titleize%></div> <div class="uid"><%=authentication.uid%></div><%=link_to"X",authentication,:confirm=>'Are you sure you want to remove this authentication option?',:method=>:delete,:class=>"remove"%> </div><%end%> <div class="clear"></div> </div><%end%> <p><strong>Add another service to sign in with:</strong></p><%else%> <p><strong>Sign in through one of these services:</strong></p><%end%><!—<a href="/auth/twitter" class="auth_provider"><%=image_tag"twitter_64.png",:size=>"64x64",:alt=>"Twitter"%> Twitter</a>—><%unless@authentications.select{|a|a.provider=="facebook"}.any?%><%=link_to_functionimage_tag("facebook_64.png",:size=>"64x64",:alt=>"Facebook"),'fblogin()'%><%end%><!—<a href="/auth/google_apps" class="auth_provider"><%=image_tag"google_64.png",:size=>"64x64",:alt=>"Google"%> Google</a>—><div class="clear"></div>
First, the above step created some cruft in your routes that will make you
unhappy later. Remove the line that says get
“authentications#index” from your routing file. Your route file should contain
a trace of the authentications you plan on dealing with. Use this snippet:
You can use Facebook to let people create new accounts, but that’s left as an
exercise to the reader!
Step 4: Boot it up
Issue a command to start your server:
Terminal
1
bundle exec foreman start
Since setting environment variables is important to the application running
properly, rails s probably won’t work any longer! Foreman will put
us in good position to manage environment variables (and pull user social
graphs via Sidekiq later!)
You should be able to click through to the
Acknowledgements:
Many of the file contents are avialable in this gist.
The amazing RailsCasts series provided not one but two pieces of this finished puzzle. Thanks, Ryan!
I haven’t blogged since the last Startup Weekend in Charlotte! Must mean it’s time for another one, as the next Startup Weekend approaches.
First is Charlotte Startup Weekend 3, where I am a co-organizer. You can read our kickoff blog for CSW3 on our site. We also have testimonials from technologists and business people. This is a great event for working on a project for the fun of it, and making friends and connections in the Charlotte startup community at the same time.
It’s November 4-6, so it’s in a few weeks. We have a lot of sponsors, judges, advisors and volunteers to introduce, but we need attendees! If you cannot afford the registration fees, please contact me, as there may be some scholarship possibilities.
If you’re not sure whether Startup Weekend is right for you, there’s an event from Collaborate CLT and CLT Launch hosted by Packard Place to help you evaluate that on Tuesday, October 25.
Finally, if you are interested in the Charlotte startup community, I publish a newsletter that attempts to circulate great information about what’s happening and who is involved here in the city. You can view the archives or sign up!
For those of you who are learning of my existence for the first time, welcome! I’m writing today about my involvement with Charlotte Startup Weekend 2, but I have to start with some of my own background to help you understand why you should be involved as well.
I came to Charlotte in January of 2008 to pursue my professional passion of working with Ruby on Rails. I selected a Charlotte startup over one in the Bay Area because I believed in the business. During our time here, my wife and I have come to love Charlotte deeply, and have made it our home. I am an advocate for Charlotte, and I’m also an admirer and exhibitor of its entreprenurial spirit. After moving here for one Charlotte startup, I’ve founded or co-founded two others, and joined a fourth as its CTO.
I am co-organizing Charlotte Startup Weekend 2. I am donating my time because I believe in the format, and that it’s exactly what Charlotte’s maturing entrepreneurial environment needs to take the next step. During my time as a freelance consultant doing networking in Charlotte, I came to be familiar with a great deal of this city’s talent in design, software development, marketing, and entrepreneurship. I believe it’s time for this claim that I know to be true to become widely believed: this city has an incredible talent base and tremendous potential. By participating in Charlotte Startup Weekend, you’ll be teaming with some of Charlotte’s best and brightest for an inspiring weekend of networking, friendship, and working together.
The agenda is available on the CSW2 website, but here is a summary. On Friday night, after opening remarks, those who have an idea they’d like to put before the group to create will pitch their concept. A small number of those concepts will be selected, and teams will self-organize based on what and who they’d like to work with. Work will begin. Food and drink will be provided. Advisors will review and offer commentary on your progress. At the end of the weekend, a panel of judges will decide who has won. Depending on the organizers meeting their sponsorship goals, there may be prizes awarded the winners. Perhaps our winner will have an opportunity to become tenants at our host sponsor, Packard Place!
I’d exhort us all to build new companies together here in Charlotte. Practicing will make us better, and you could meet your next business partner at this event. You’ll have a chance to know what everyone on your team is capable of, and you’ll be comparing results with your peers for weeks to come. You’ll look at what has been accomplished by a group of strangers in one weekend, and you’ll wonder what’s possible in your own business with your own teams in the next two weeks.
So, go register!. And if you are interested in sponsorship, please contact me at jim at jimvanfleet.com and reference CSW in your subject line.
DevOps Culture Hacks | DevOps.com: “A turning point for Jesse in terms of moving from an obstacle in the way of change to someone that really knew how to add value with ops practice stemmed from a battle he got into with the ‘VP of Awesome’ at Amazon. This was the nickname of this particular VP because it seemed that pretty much any highly interesting project at Amazon was under this man’s purview. What happened was that Jesse did not want to let out a piece of software because he knew, for sure, that it would bring the site down. The VP overrode him by saying that the site may go down, but the stock price will go up. So, the software went out, and it brought the site down. Two days of firefighting and the site came back up, and so did the stock price, and so did the volume of orders.
The dev team went on and had a party, they were rewarded for job well done, new and profitable functionality released. At the end of the year, Ops got penalized for the outage! Amazon rewarded development for releasing software and providing value and operations was not a part of that. They were in fact penalized for something that was out of their control.”
In the next two weeks, I expect the following events:
I will speak at Ignite! Charlotte for a second time, this time in front of a sold-out Neighborhood Theater.
My wife Megan and I will have a pre-natal visit and our last ultrasound before the birth of our first child, a son, in April.
My wife’s parents will make their first visit to Charlotte, bringing their dogs with them. We will have ten living creatures in the house.
I will turn 32.
My wife will have a baby shower.
My parents will visit with the intention of selecting a new home for themselves, here in Charlotte. After that selection, I expect the logistics of their move to be made in a short amount of time.
I will attend a meeting of CRTEC which promises to become the home of Charlotte’s technology leadership, followed by a meeting with another CRTEC member to discuss our vision of Charlotte’s software development community.
I will attend an all-day workshop for entrepreneurs focused on preparing for investment and attracting investors to small businesses, put on by the BIG council in conjunction with the SBTDC.
I will submit a talk for RailsConf 2011.
Megan and I will attend a Punch Brothers show at the Neighborhood Theater. Chris Eldridge is a dear friend of Megan’s.
I will celebrate the one year anniversary of going freelance with it’s bspoke.
Adam Howell and I will observe the one year anniversary of Work Montage and our product Mocksup.
And finally, although a more formal announcement will be forthcoming, I’ve altered bspoke’s charter to accept a full-time CTO position at Otherscreen, a web and mobile startup here in Charlotte, NC. It is a true privilege to be working with this team already, and you should expect big things.
That’s in addition to client work and the particulars of every day life. If I am overly quiet or missing for a good portion of February, now you know why. If I owe you something, please keep reminding me. Except for you, Raquel, I’m almost done with your recommendation.
Unqualified Reservations: What’s wrong with CS research: “So here’s the first thing that’s wrong with CS research: there’s no such thing as CS research. First, there is no such thing as ‘computer science.’ Except for a few performance tests and the occasional usability study, nothing any CS researcher does has anything to do with the Scientific Method. Second, there is no such thing as ‘research.’ Any activity which is not obviously productive can be described as ‘research.’ The word is entirely meaningless. All just semantics, of course, but it’s hardly a good sign that even the name is fraudulent.
When we look at what ‘CS researchers’ actually do, we see three kinds of people. We can describe them roughly as creative programmers, mathematicians, and bureaucrats.”
To excerpt from this post does it a great disservice, and, like most other things I post to my blog, is highly recommended reading.
From my time in undergraduate CS studies at a prestigious university (attached to the programming languages team, for good measure!), I can both accept and amend the author’s central claim: CS research sucks.
I worked on a team working on an optimizing compiler for the Java language that could detect when known transforms could be applied yielding a semantically equivalent, but faster, set of bytecodes. The platform gets marginally faster for everyone, should the research yield meaningful fruit and get adopted upstream. A noble goal, undertaken by earnest and intelligent men and women, but ultimately doomed.
One note the author does not strike is of the commercial nature of programming languages. Over and over, we see the pattern: evangelism, adoption, glut of choice, everything starts to suck and get vendor dependent, death. After its acquisition by Oracle, to the author’s “creative programmers”, Java is now in its final stage, destined to live as a zombie whose musculature (the JVM) is kept alive only by newer languages (e.g. Scala, Clojure, JRuby, Groovy, etc.) that target the platform. This fact should not be lost on the judgement of quality of CS research.
On the other side of the equation, programming an IDE that supported an alternative implementation of the generics which became part of the Java language in JDK 1.5 introduced me to basically all of the concepts I use still today as a successful programmer. It wasn’t because of the work I did faked on writing the grammar for this extended language, it was because of the techniques we used as a team in writing the IDE. Pair programming, test driven development, The Pragmatic Programmer, etc. It’s hard for me to think of that being a failure. I love programming, and it’s because of my time with the PLT team at Rice University. Thanks, Dr. Cartwright!