diff --git a/app/controllers/services_controller.rb b/app/controllers/services_controller.rb
index 4d89e530308fb24dc0cff03e45bcd5e139108d4a..c2abfaf1ef0085ee170ad173f927ce4f0a160303 100644
--- a/app/controllers/services_controller.rb
+++ b/app/controllers/services_controller.rb
@@ -19,11 +19,12 @@ class ServicesController < ApplicationController
     provider = auth['provider']
     user     = auth['user_info']
 
-    current_user.services.create(:nickname => user['nickname'],
-                                 :access_token => toke, 
-                                 :access_secret => secret,
-                                 :provider => provider, 
-                                 :uid => auth['uid'])
+    service = "Services::#{provider.camelize}".constantize.new(:nickname => user['nickname'],
+                                                               :access_token => toke, 
+                                                               :access_secret => secret,
+                                                               :provider => provider,
+                                                               :uid => auth['uid'])
+    current_user.services << service
 
     flash[:notice] = I18n.t 'services.create.success'
     if current_user.getting_started
diff --git a/app/models/service.rb b/app/models/service.rb
index d331fb46c83d216cb0966d91c2b6ad70034e24ba..93bd741cb4c4b53773bd4e6b822b882b9cd7b893 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -13,4 +13,11 @@ class Service
   key :access_secret, String
   key :nickname, String
   timestamps!
+
+  def public_message(length, url = "")
+    space_for_url = url.blank? ? 0 : (url.length + 1)
+    truncated = truncate(self.message, :length => (length - space_for_url))
+    truncated = "#{truncated} #{url}" unless url.blank?
+    return truncated
+  end
 end
diff --git a/app/models/services/facebook.rb b/app/models/services/facebook.rb
new file mode 100644
index 0000000000000000000000000000000000000000..338416e6bcd72c5e157a1470f2889f860fb8abb0
--- /dev/null
+++ b/app/models/services/facebook.rb
@@ -0,0 +1,10 @@
+class Services::Facebook < Service
+  def post(message)
+    Rails.logger.debug("event=post_to_service type=facebook sender_id=#{self.user_id}")
+    begin
+      RestClient.post("https://graph.facebook.com/me/feed", :message => message, :access_token => self.access_token) 
+    rescue Exception => e
+      Rails.logger.info("#{e.message} failed to post to facebook")
+    end
+  end
+end
diff --git a/app/models/services/twitter.rb b/app/models/services/twitter.rb
new file mode 100644
index 0000000000000000000000000000000000000000..373dbdf23881774572d5d52a42d425c6a6cd5792
--- /dev/null
+++ b/app/models/services/twitter.rb
@@ -0,0 +1,21 @@
+class Services::Twitter < Service
+  def post(message)
+   Rails.logger.debug("event=post_to_service type=twitter sender_id=#{self.user_id}")
+
+    twitter_key = SERVICES['twitter']['consumer_key']
+    twitter_consumer_secret = SERVICES['twitter']['consumer_secret']
+
+    if twitter_consumer_secret.blank? || twitter_consumer_secret.blank?
+      Rails.logger.info "you have a blank twitter key or secret.... you should look into that"
+    end
+
+    Twitter.configure do |config|
+      config.consumer_key = twitter_key
+      config.consumer_secret = twitter_consumer_secret
+      config.oauth_token = self.access_token
+      config.oauth_token_secret = self.access_secret
+    end
+    
+    Twitter.update(message)
+  end
+end
diff --git a/app/models/status_message.rb b/app/models/status_message.rb
index 92b5dd02fe70dc7a08a878a37f0c1d03ffc56340..33b7d4c8c14787d25b57a55e509206f2165f1ce3 100644
--- a/app/models/status_message.rb
+++ b/app/models/status_message.rb
@@ -6,6 +6,7 @@ class StatusMessage < Post
   include Diaspora::Socketable
   include YoutubeTitles
   require File.join(Rails.root, 'lib/youtube_titles')
+  include ActionView::Helpers::TextHelper
   
   validates_length_of :message, :maximum => 1000, :message => "please make your status messages less than 1000 characters"
   xml_name :status_message
@@ -21,7 +22,7 @@ class StatusMessage < Post
     get_youtube_title message
   end
   def to_activity
-        <<-XML
+    <<-XML
   <entry>
     <title>#{self.message}</title>
     <link rel="alternate" type="text/html" href="#{person.url}status_messages/#{self.id}"/>
@@ -31,7 +32,15 @@ class StatusMessage < Post
     <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
     <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
   </entry>
-        XML
+      XML
+  end
+
+
+  def public_message(length, url = "")
+    space_for_url = url.blank? ? 0 : (url.length + 1)
+    truncated = truncate(self.message, :length => (length - space_for_url))
+    truncated = "#{truncated} #{url}" unless url.blank?
+    return truncated
   end
 
   protected
diff --git a/app/models/user.rb b/app/models/user.rb
index 849d50355089309a4bcb0c86de817d72cf2dc48e..b6d2af2c4fe93c0b4129bb10071aef3e04c89f80 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -166,40 +166,11 @@ class User
       end
 
       self.services.each do |service|
-        self.send("post_to_#{service.provider}".to_sym, service, message)
+        service.post(message)
       end
     end
   end
 
-  def post_to_facebook(service, message)
-    Rails.logger.debug("event=post_to_service type=facebook sender_handle=#{self.diaspora_handle}")
-    begin
-      RestClient.post("https://graph.facebook.com/me/feed", :message => message, :access_token => service.access_token)
-    rescue Exception => e
-      Rails.logger.info("#{e.message} failed to post to facebook")
-    end
-  end
-
-  def post_to_twitter(service, message)
-    Rails.logger.debug("event=post_to_service type=twitter sender_handle=#{self.diaspora_handle}")
-
-    twitter_key = SERVICES['twitter']['consumer_key']
-    twitter_consumer_secret = SERVICES['twitter']['consumer_secret']
-
-    if twitter_consumer_secret.blank? || twitter_consumer_secret.blank?
-      Rails.logger.info "you have a blank twitter key or secret.... you should look into that"
-    end
-
-    Twitter.configure do |config|
-      config.consumer_key = twitter_key
-      config.consumer_secret = twitter_consumer_secret
-      config.oauth_token = service.access_token
-      config.oauth_token_secret = service.access_secret
-    end
-
-    Twitter.update(message)
-  end
-
   def post_to_hub(post)
     Rails.logger.debug("event=post_to_service type=pubsub sender_handle=#{self.diaspora_handle}")
 
diff --git a/spec/controllers/services_controller_spec.rb b/spec/controllers/services_controller_spec.rb
index 23dfe2f328b3e2384c4812680ec6607873e68822..57e60ebf6cadbbe57423105bdb27a12350967735 100644
--- a/spec/controllers/services_controller_spec.rb
+++ b/spec/controllers/services_controller_spec.rb
@@ -9,10 +9,6 @@ describe ServicesController do
   let(:user) { make_user }
   let!(:aspect) { user.aspects.create(:name => "lame-os") }
 
-  let!(:service1) {a = Factory(:service); user.services << a; a}
-  let!(:service2) {a = Factory(:service); user.services << a; a}
-  let!(:service3) {a = Factory(:service); user.services << a; a}
-  let!(:service4) {a = Factory(:service); user.services << a; a}
 
   let(:mock_access_token) { Object.new }
 
@@ -29,6 +25,11 @@ describe ServicesController do
   end
 
   describe '#index' do
+    let!(:service1) {a = Factory(:service); user.services << a; a}
+    let!(:service2) {a = Factory(:service); user.services << a; a}
+    let!(:service3) {a = Factory(:service); user.services << a; a}
+    let!(:service4) {a = Factory(:service); user.services << a; a}
+
     it 'displays all connected serivices for a user' do
       get :index
       assigns[:services].should == user.services
@@ -54,9 +55,18 @@ describe ServicesController do
       post :create
       response.should redirect_to services_url
     end
+
+
+    it 'creates a twitter service' do
+      user.getting_started = false
+      request.env['omniauth.auth'] = omniauth_auth
+      post :create
+      user.services.first.class.name.should == "Services::Twitter"
+    end
   end
 
   describe '#destroy' do
+    let!(:service1) {a = Factory(:service); user.services << a; a}
     it 'should destroy a service of a users with the id' do
       lambda{delete :destroy, :id => service1.id.to_s}.should change(user.services, :count).by(-1)
     end
diff --git a/spec/models/services/facebook_spec.rb b/spec/models/services/facebook_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b239b4ac58bc479d19c0d0e59dd63d922faac1e2
--- /dev/null
+++ b/spec/models/services/facebook_spec.rb
@@ -0,0 +1,23 @@
+require 'spec_helper'
+
+describe Services::Facebook do 
+
+  before do
+    @user = make_user
+    @user.aspects.create(:name => "whatever")
+    @post = @user.post(:status_message, :message => "hello", :to =>@user.aspects.first.id)
+    @service = Services::Facebook.new(:access_token => "yeah")
+    @user.services << @service
+  end
+
+  describe '#post' do
+    it 'posts a status message to facebook' do
+      RestClient.should_receive(:post).with("https://graph.facebook.com/me/feed", :message => @post.message, :access_token => @service.access_token) 
+      @service.post(@post.message)
+    end
+    it 'swallows exception raised by facebook always being down' do
+      RestClient.should_receive(:post).and_raise
+      @service.post(@post.message)
+    end
+  end
+end
diff --git a/spec/models/services/twitter_spec.rb b/spec/models/services/twitter_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..63720a3505d9aa67585448fb0b6864f42639edd9
--- /dev/null
+++ b/spec/models/services/twitter_spec.rb
@@ -0,0 +1,19 @@
+require 'spec_helper'
+
+describe Services::Twitter do 
+
+  before do
+    @user = make_user
+    @user.aspects.create(:name => "whatever")
+    @post = @user.post(:status_message, :message => "hello", :to =>@user.aspects.first.id)
+    @service = Services::Twitter.new(:access_token => "yeah", :access_secret => "foobar")
+    @user.services << @service
+  end
+
+  describe '#post' do
+    it 'posts a status message to twitter' do
+      Twitter.should_receive(:update).with(@post.message) 
+      @service.post(@post.message)
+    end
+  end
+end
diff --git a/spec/models/status_message_spec.rb b/spec/models/status_message_spec.rb
index ea4520c9eb6c4111b53f76f875cd8eb9691214aa..53cd3e8c5828680f8549db900ebd0854dece6d08 100644
--- a/spec/models/status_message_spec.rb
+++ b/spec/models/status_message_spec.rb
@@ -72,8 +72,26 @@ describe StatusMessage do
       post.save!
       post[:youtube_titles].should == {video_id => expected_title}
     end
-
   end
 
-end
+  describe '#public_message' do
+    before do
+      message = ""
+      440.times{message << 'd'}
+      @status_message = @user.post(:status_message, :message => message, :to => @aspect.id)
+    end
+
+    it 'truncates the message' do
+      @status_message.public_message(140).length.should == 140
+      @status_message.public_message(420).length.should == 420
+    end
 
+    it 'has the correct length if a url is present' do
+      @status_message.public_message(140, "a_url_goes_here").length.should == 140
+    end
+
+    it 'adds the public link if present' do
+      @status_message.public_message(140, "/p/#{@status_message.id}").should include "/p/#{@status_message.id}"
+    end
+  end
+end
diff --git a/spec/models/user/posting_spec.rb b/spec/models/user/posting_spec.rb
index 48b8ba604d1a819499458ecdea6f4faf6a847178..f587886ad943d6e30c0803fd9e87be104629ec8b 100644
--- a/spec/models/user/posting_spec.rb
+++ b/spec/models/user/posting_spec.rb
@@ -70,9 +70,13 @@ describe User do
 
   end
 
+
+  describe 'services'
+
   describe '#dispatch_post' do
     include Rails.application.routes.url_helpers 
     let(:status) {user.build_post(:status_message, @status_opts)}
+
     before do
       @message = "hello, world!"
       @status_opts = {:to => "all", :message => @message}