Playing with Ruby

Ruby is a wonderful programming language, and when I say wonderful I mean that basically it just makes you happy. As a Java programmer, there are so many things that I need to check and be careful about, and Ruby just makes it easier for you, taking care of you, and if I have one more glass of wine I might get carried away and say that it almost spoils you, makes you lazy – cause now when I have to implement an algorithm, I’d rather do it in Ruby rather than Java, or even PHP, which is still easier, but with all the ugly $-signs (yes, I am lazy when it comes to hold the shift key and press ‘4’, who’s the dumb-a$$ that came up with that stupid idea anyways, ha ?)

One of the things I first do when starting to learn a programming language is implementing a few basic stuff, for example, the famous Tower of Hanoi:

def hanoi(disc, src, hlp, dst)
    if disc > 0
        hanoi(disc-1, src, dst, hlp)
        puts "moving disc #{disc} from #{src} to #{dst}"
        hanoi(disc-1, hlp, src, dst)
    end
end

hanoi(3, 'src', 'hlp', 'dst')

It’s so beautiful to define factorial in one line:

def fact(n) (1..n).inject{|r,i| r*i } end 

And then I usually continue to merge-sort:

# sorting the array from _start index to the _end index
# using merge sort
def mergesort(arr)

    # stop condition
    return arr if arr.count == 0 || arr.count == 1 
    # split the range
    mid = arr.count/2

    # sort recursively both parts
    arr1 = mergesort(arr[0, mid]) 
    arr2 = mergesort(arr[mid, arr.count-mid])

    # and merge
    merged = []
    max_i, max_j = [arr1.count, arr2.count]
    i = j = 0
    while i < max_i && j < max_j
        if arr1[i] <= arr2[j]
            merged << arr1[i]
            i += 1
        else
            merged << arr2[j]
            j += 1
        end
    end

    # continue copying the rest:
    while i < max_i
        merged << arr1[i]
        i += 1
    end
    while j < max_j
        merged << arr2[j]
        j += 1
    end

    # return
    merged
end

arr = [2,3,4,5,6,1,7]
puts mergesort(arr)        	

and if we didn’t have enough, let’s implement quicksort as well:

def quick(arr)
  return [] if (arr.size == 0)    
  pivot = arr.pop
  left = Array.new
  right = Array.new
  arr.each { |i|
    if i < pivot
      left << i
    else
      right << i
    end
  }
  return quick(left) + [pivot] + quick(right)
end

a = [5,3,9,8,7,2,4,1,6,5]
p quick(a)

The downside of coding in an unfamiliar language is that your’e still captured in patterns that are perfect for other programming languages, only that in this one – you can do things in a more elegant & efficient way.

Until next time…ta-ta!

Playing with Ruby

NOP people and learning Ruby

Some people can’t just sit and do nothing, I know that cause I’m one of them… I call these people: *NOP people. Even a ride on the elevator is just enough time to check emails and tweeter, and that’s also why I always need a side project. Last year I committed to PHP and MySQL (LAMP), even though I read some awful things about it, I decided to learn some PHP because there are so many CMSs built with LAMP:WordPress, Drupal, Joomla… and carts as well: Magento, Zen cart, Open cart

For year 2013 I decided to learn Ruby and Ruby on Rails. For those of you who don’t know the difference, it’s simple:

Ruby – scripting language that has many cool features such as dynamic typing (also known as “duck typing”)

Ruby on Rails – web framework for Ruby that provides many libraries that’ll make your life much easier. RoR, like Ruby, is provided free and is open source.

I have to admit that until the end of February I thought that Python will be the winner but then I ran into Rubymonk and it just caught me. In parallel to Rubymonk, I re-solved about 30 challenges in codeeval – because of the first rule of programming: you can’t learn a new language just by reading!

When I started coding in Ruby, I was looking for a good IDE for Mac and after some Googling work I decided on Sublime Text Editor. It takes a little time getting used to it, but when you learn shortcuts like command+R – jump to another function, or, command + P – to browse between files, and the very convenient tab completion (ife, tab for if-else-end for example) and many other shortcuts which you can browse yourself by typing command + shift + P. God bless sublimeText!

I didn’t take any of the in from Try Ruby but I bet that they’re good, and I can say that because I took a few classes in Rails for Zombies and it was fun! I would definitely check out the other classes in codeschool.

On my next NOP of course..

______________________________________________________________________________.

*NOP – In computer science, NOP or NOOP (short for No Operation) is an assembly language instruction, sequence of computer programming language statements, or computer protocol command that effectively does nothing at all. (from wiki)

NOP people and learning Ruby

Patent troll Uniloc takes a hit

A few months ago I wrote a post about intellectual property telling the story of a small company called Laminar Research which might be forced to shut-down due to a lawsuit they’re facing.

Well, I was glad to read this morning that the same patent-troll, Uniloc, got their claim against Rackspace dismissed by a chief judge Leonard Davis which based his ruling on U.S. Supreme Court case law that prohibits the patenting of mathematical algorithms. This is the first reported instance in which, an early motion to dismiss finding a patent invalid because it claimed unpatentable subject matter, is granted.

Rackspace, even though being way bigger than Laminar research, still needed Red Hat support which provided Rackspace’s defense. Laminar research were not that fortunate. Just a thought.

Patent troll Uniloc takes a hit

Using API to create single-click order experience

On the previous posts we went over the different options of online payment processing and then dived a bit deeper into a discussion about how user-experience effects the conversion and how can we improve both by using an API.

The last two examples showed how to use an API in order to create a shopper entity on Bluesnap servers and then use it with a token (which was generate by the API as well) in order to “log the shopper into” a buy page, meaning, redirect the shopper to a buy-page where all his information (except the billing information) is pre-filled. The reason we couldn’t pre-fill the billing info is due to regulations forced on us by the credit-card companies: a merchant which is not PCI compliant, should not hold billing information records of his/her customers. It sounds like this restriction sucks, but it’s actually very good since it forces us to protect our clients data!

That said, we still want to provide the best customer experience to our shoppers, and by using an API we can do just that. The last post gave us the “taste” of what can be achieved and now we’ll see the “real thing”: after a shopper already placed an order and bought one of our products, we may offer the customer a promo-code for future purchase or an upgrade for a reduced price etc. Even though we don’t have the shopper’s billing information the processor (Bluesnap) does – and we’ll take advantage of it to create a single-click order experience.

Since we created the shopper entity we have a “shopper-id” (unique identifier for a shopper – supplied by the processor) which we can use to place future orders:

<?php
/*
 * Written By: Ben Hultin & Nir Alfasi (alfasin)
 * Nov. 2012
 * 
 * This code is used to call an API (RESTful) service of Bluesnap that places an order on Bluesnaps' backend.
 * We chose using CURL to place the API request in this demo, but we urge anyone who implements an API client 
 * to work with a RESTful API client framework in order to have a full support of all the properties of REST, such as: 
 * set HTTP method, get return-code, read/write headers, full XML support etc.
 * 
 * The API manual is available under "Developer Toolbox" section: 
 * http://www.bluesnap.com/helpcenter/Static/default.htm?bluesnap_web_services.htm
 * 
 */

//here we define $credentials = $username . ":" . $password;
include_once('../credentials.php'); 



/**
 * Retrieve data from input fields
*/ 
$shopperId = $_REQUEST['shopper-id'];   		
$cardLastFour = $_REQUEST['card-last-four-digits'];     		 
$cardType = $_REQUEST['card-type'];
$skuId = $_REQUEST['sku-id'];
$amount = $_REQUEST['amount'];
$currency = $_REQUEST['currency'];
  

/**
 * Assemble the XML string with variables instantiated above
*/  
$xmlToSend = '<order xmlns="http://ws.plimus.com">
 <soft-descriptor></soft-descriptor>
   <ordering-shopper>
    <credit-card>
                  <card-last-four-digits>'.$cardLastFour.'</card-last-four-digits>
                  <card-type>'.$cardType.'</card-type>
    </credit-card>
    <shopper-id>'.$shopperId.'</shopper-id>
            <web-info>
                <ip>'.$ipAddress.'</ip>         
                <remote-host>bzq-219-121-253.static.bezeqint.net.reinventhosting.com</remote-host>
                <user-agent>Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; GTB6.3; .NET CLR 2.0.50727)</user-agent>
                <accept-language>en-us</accept-language>
            </web-info>
   </ordering-shopper>
   <cart>
      <cart-item>
         <sku>
            <sku-id>'.$skuId.'</sku-id>
         </sku>
         <quantity>1</quantity>
        </cart-item>
   </cart>
   <expected-total-price>
      <amount>'.$amount.'</amount>
      <currency>'.$currency.'</currency>
   </expected-total-price>
</order>';
        
        
/**
 * Initialize handle and set options
*/
$url = 'https://sandbox.plimus.com/services/2/orders/';

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_HTTPHEADER, Array("Content-Type: application/xml"));
curl_setopt($ch, CURLOPT_USERPWD, "$credentials");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlToSend);	
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);


/**
 * Execute Curl call and display XML response
*/
$response = curl_exec($ch);
curl_close($ch);

echo show_xml($response);
?>

By clicking on the following link you’ll place a (single-click) order in Bluesnap’s sandbox using the API code displayed above.

Using API to create single-click order experience

Improving Customer-Experience and Conversion with API

Important: all the links and the code-examples that are embedded in this post, link toPlimus service in  Bluesnap’s sandbox – so feel free to play with it – all the credit-card charges are not real!

On the previous post , we talked a bit about the different options of online payment-processing and now it’s time to talk about the “how”.

One of the nightmares of every marketer is abandoned carts, in this post we’ll see how you can use an eCommerce API in order to create a better shopper experience and as a result to improve the conversion rate.

There are so many theories that deal with customization of a Buy-Page , lists of Do’s andDon’ts  and so on and so forth . People like to think that there’s some secret formula that once applied – conversion will rocket high.

The truth is that there are many different truths that apply to different types of businesses, for example, if your online store sells SSL-certificates or Anti-virus software (or any other protection-software like firewalls) you really should have a ’Hacker Safe’ logo or something alike – your buyers WILL look for it on their checkout page and if it won’t be there – it will be a little suspicious…

There are products for which you’d better customize a single-checkout page process (letting the customer enter his personal details and credit-card information on the same page), such a single checkout page usually works fine for low-price items, but if your product includes shipping, for example, then a two-pages checkout will work better in most of the cases.

Like I said – there’s no “secret trick” and if you want to confirm that you did a good job, A/B testing should be applied (if you can’t measure it – you can’t prove that it works!).

Still, there are a few “universal truths” that can be applied to your store, and this is what we’re going to deal with in this post, so roll your sleeves up and let’s get to work!

If your website support user-registration, making the shopper enter ALL his personal information AGAIN in the checkout page is not a very nice user experience to say the least. That’s exactly why we should use the create-shopper API call . An example of how it works can be viewed here . As you can see, the PHP code is pretty simple and short (if you remove the comments you’ll see that it’s about 60 lines of code):

<?php

/*
 * Written By: Ben Hultin & Nir Alfasi (alfasin)
 * Nov. 2012
 * 
 * This code is used to call an API (RESTful) service of Bluesnap that creates a shopper entity on Bluesnaps' backend.
 * The shopper-entity can be used, later-on, for one-click purchases, to automate charges, to retrieve orders history and more.
 * We chose using CURL to place the API request in this demo, but we urge anyone who implements an API client 
 * to work with a RESTful API client framework in order to have a full support of all the properties of REST, such as: 
 * set HTTP method, get return-code, read/write headers, full XML support etc.
 * 
 * Documentation on "create shopper" service can be found here: 
 * http://home.plimus.com/DocumentationCenter/Static/Plimus%20Web%20Services_create_shopper.htm
 * 
 * The API manual is available under "BuyAnyware" section: 
 * http://home.plimus.com/DocumentationCenter/Static/default.htm
 * 
 * This code example is also available from: 
 * https://alfasin.com/api/create_shopper.html
 *
 * and if you want to see it "in action": 
 * https://alfasin.com/create_shopper.php
 * 
 */
    

    // In the response of "create-shopper" API call we'll receive the 
    // newly created shopper-id which we should extract from the Location header. 
    // An example for such header: 
    // 
    // ...
    // Location: https://sandbox.plimus.com/services/2/shoppers/19372564
    // ...
    function get_shopper_from_header($ch, $string) {
        global $shopper_id;       
        //looking for the "Location" header - but since it's case insensitive...
        if(strpos($string, "ocation") > -1){ 
            $tokens = explode("/", $string);
            //the shopper-id will always be the last token
            $shopper_id = trim($tokens[count($tokens)-1]); 
        }  
        return strlen($string);
    }

   // TODO: Change the following URL to our rackspace machine
   // An example of how to call this PHP code:
   // https://alfasin.com/blog/code/create_shopper.php?firstName=bob&lastName=Smith&email=bob.Smith@gmail.com&address1=123 Main Street&address2=Apt K-9&city=Parkville&state=TN&country=us&phone=411-555-1212&zipcode=37027

   // read the request parameters and handle special chars 
   $firstName = htmlspecialchars($_REQUEST['firstName']);     	 
   $lastName  = htmlspecialchars($_REQUEST['lastName']);     		 
   $email     = htmlspecialchars($_REQUEST['email']);                    
   $address1  = htmlspecialchars($_REQUEST['address1']);
   $address2  = htmlspecialchars($_REQUEST['address2']);
   $city      = htmlspecialchars($_REQUEST['city']);
   $state     = htmlspecialchars($_REQUEST['state']);
   $country   = htmlspecialchars($_REQUEST['country']);
   $zipCode   = htmlspecialchars($_REQUEST['zipcode']);
   $phone     = htmlspecialchars($_REQUEST['phone']);
      
   // EXAMPLE INPUT
   // -------------
 $firstName = 'Bob';   		 
 $lastName = 'Smith';     		 
 $email = "bob.smith@plimus.com";      
 $address1 = "123 Main Street";
 $address2 = "Apt K-9";
 $city = "Parkville";
 $state = "TN";
 $country = "us";
 $zipCode = "37027";
 $phone = "411-555-1212";
   

   // In the following XML (which will be embedded in the BODY of the HTTP request) 
   // the <web-info> element supposed to hold customers' information (IP, browser type etc) 
    $xmlToSend = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>
    <shopper xmlns=\"http://ws.plimus.com\">
          <shopper-info>
                <shopper-contact-info>
                      <first-name>". $firstName ."</first-name>
                      <last-name>". $lastName ."</last-name>
                      <email>". $email ."</email>
                      <address1>". $address1 ."</address1>
                      <city>". $city ."</city>
                      <zip>". $zipCode ."</zip>
                      <country>". $country ."</country>
                      <state>". $state ."</state>
                      <phone>". $phone ."</phone>
                </shopper-contact-info>
                <locale>en</locale>
          </shopper-info>          
          <web-info> 
                <ip>62.219.121.253</ip>
                <remote-host>bzq-219-121-253.static.bezeqint.net.reinventhosting.com</remote-host>
                <user-agent>Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; GTB6.3; .NET CLR 2.0.50727</user-agent>
                <accept-language>en-us</accept-language>
          </web-info>
    </shopper>";

    // Set values for the POST HEADERS:
    // The URL sets the REST resource which is being called 
    $service = 'https://sandbox.plimus.com/services/2/shoppers';
    // for the sandbox testing account TODO: include this parameter from another file and remove explicit credentials from the code
    $credentials = 'XXX:YYY'; 
    $contentType = array('Content-type: application/xml');
    
    // Initialize handle and set options
    $ch = curl_init();
    // more info about setopt options can be found here: http://www.php.net/manual/en/function.curl-setopt.php
    curl_setopt($ch, CURLOPT_URL, $service); 
    curl_setopt($ch, CURLOPT_USERPWD, $credentials); // authentication (credentials) string encoded in base-64 
    
    curl_setopt($ch, CURLOPT_HEADER, true);          // include the headers in the output
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);  // don't output the response to screen (default behavior)
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlToSend);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $contentType);    
    curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'get_shopper_from_header');
    
    // The following switches are needed only when running in development-mode on localhost
    //    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);  // follow redirects recursively 
    //    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // default value is "2": "check the existence of a common name and also verify that it matches the hostname provided" - we need to turn it off
    //    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // "stop cURL from verifying the peer's certificate"
    
    // For debugging purposes - we can ask the remote server to include all the request-headers in the response
    //    curl_setopt($ch, CURLINFO_HEADER_OUT, true);
    

    // Execute the request and example code to time the transaction
    $response = curl_exec($ch);           
    // if a shopper was successfully created we should receive "201 created" response code
    // and the shopper-id will be extracted into $shopper_id by get_shopper_from_header() which will iterate the response headers
     
    // Check for errors
    if ( curl_errno($ch) ) {
        echo 'HTTP error code: ' . curl_errno($ch) . '<br>error-message: "' . curl_error($ch) . '"';
        return;
    } 

    // SUCCESS
    if (is_numeric($shopper_id)) {
	echo '<br>
              A new shopper entity was created on our servers with shopper-id: '
              . $shopper_id .
              '<br><br>';
    }
    // FAIL
    else {
        echo '<br><br>
              <font color="red"><b>Something went wrong!</b></font>
              <br>
              Server reponse:
              <br><br>
              <pre style="display: block; font-family: monospace; white-space: pre; margin: 1em 0px;">'
              . $response .
              '</pre><br>';
    }
?>

This code is using what we call  authentication-token auto-login API call . If we scroll back a bit and click again on the “create-shopper” demo, we can see that in the response we receive a shopper-id. This ID can be used in order to generate an authentication token which in return can be used to auto-login the shopper into one of the buy-pages (step-1 and step-2) or into the shopper control-panel.

On the next post we’ll implement a real single-click purchase process after which I’ll explain the PCI-compliance issue involved and lay-out how can we work around it (in a legit way of course!) until then, you can enjoy the Harlem shake in the bitwise version

Improving Customer-Experience and Conversion with API

Online Payment Processing

ecom

I started writing a post that demonstrates how a vendor can use API calls in order to create a better shopping experience and help convert shoppers into buyers. But after a few lines I figured that there is a basic terminology and motivation that might be obvious to me (since I worked in the eCommerce industry for the last 6 years) but not necessarily to the readers… So I decided to write a “pre-post” that will provide an overview about online payment-processing  – and only then I’ll move on to implementing API calls and suggestions to improve your conversion rate.

There are many developers out there that build cool software, apps, plugins etc – but have no idea how to sell it. Some of them just open a Paypal/Google wallet/Authorize.NET account, implement their API/HTTP-redirect and think that they’ve done the best thing possible. Well, think again!

Let’s start with some

Definitions & Terminology

Payment Gateway” or “Payment Processor” – In order to simplify things, we’ll treat the two as the same: a company or a third party in which the merchant (developer) opens a merchant-account and which processes transactions by moving the money from the customer’s issuing bank to the merchants’ bank.

Motivation

There are two major problems with Paypal/G-Wallet/Authorize.NET:

1. You, the developer, need to take care (implement) all the possible scenarios:  success, and possible failure reasons (display the proper error), calculate the currency conversion rates, hedge the amount in case the currency-rates change dramatically and the customer asks for a refund (or alternatively, lose money…) and that’s only part of the list of issues that should be handled.

2. Localization: there are so many potential-customers in other parts of the world that won’t buy since your buy-page is not translated to their language and the payment options you offer are not popular in their countries. For example, in the Netherlands (where you process in Euros) there’s a payment method that most of US residents probably never heard of, called iDEAL.

If you’re a good programmer, you’ll probably work hard and solve most of the critical issues in #1, but the issues in #2 are not solvable unless you do one of the following:

  • use the services of a professional online payment processor (such as Bluesnap or DR)
  • implement a full eCommerce solution…

Of course that there are many other reasons to go with a professional online payment processing solution, and maybe the most important of which is having a fail-over mechanism, for example, if you tried to process a credit-card with Authorize.NET and Wells-Fargo returned a generic error, you can try processing the same transaction with a different gateway instead of loosing business.

Why shouldn’t I use Authorize.NET ?

You may decide to use Authorize.NET, but then you’ll loose market segments such as:

  • Businesses in countries which don’t favor credit-card transactions
  • B2B – which normaly use PO (purchase orders), check or wire transactions
  • Local customers that feel more secure using their Paypal accounts, checks or other payment options

So, When SHOULD a developer use Paypal or Authorize.NET ?

To my opinion only if you do micro-payments, or, if you belong to a small segment of businesses that process mainly local transactions in USD and target customers that use only credit-cards.

Why do I say “almost never” ?

Business owners prefer using Paypal or Authorize.NET because of the low commission-rates (around 3%) comparing to a full payment processing solution which charges somewhere between 5-15% (depends on the transaction amount). But, if we do the math, one deal that you loose because you couldn’t support the payment-method/fail-over mechanism – could “cover” a commission rate difference of another 10-15 transactions!

What I like the most about using a professional payment processing solution is that you can setup an account and start selling in less than five minutes. Want to see for yourself ? Just open an account on Bluesnap sanbox (it’s free!) and follow the go-guide to setup a product: all you have to do is choose a name, short description and a price. After a product was created – automatically the platform creates a contract/SKU – which is the *real* thing that we’ll sell. A good example to understand the difference between a Product and a Contract is to think about a product as “Microsoft Office” and the contract as “Student version” or “Home edition”. You can see that the product is an abstract entity (like a Class) while the contract is the Object or a product Instance if you will.

product-setup-300x171

product setup 1st step

product-setup-2-300x192

product setup 2nd step

Once a contract was created – you can go to the contract’ “General” settings-page (there are many configurable options – but we’ll ignore it for now), copy the “Buy-link” and paste it into your browser

contract-setup-300x157

contract setup page

it will take you to your newly sandbox buy-page. If you want to place an order – you can use a generic “Visa” credit-card: 4111-1111-1111-1111 (you can enter any 3-digits in the “Security Code” field) and place an order. An example for such a buy-page: https://sandbox.plimus.com/jsp/buynow.jsp?contractId=1711978

After you’ve gone through that – you’re ready to take the “advanced class” and start playing with the API – on which I’ll write the next post.

Disclaimer
I work for Bluesnap – an online payment-processing company, but with that said, I am not one of the owners and currently I don’t hold any shares/options!

Online Payment Processing

Blog renovation

In this world of technology using wordpres for blogging seems to be the right choice, I mean, in the last couple of months I noticed that I kept postponing writing stuff in my blog due to the overhead of maintaining my own simple html blog. So I finally took the time to install & configure WP and boy, that wasn’t simple…

I think that for non-developers it would be a quite tedious task if not impossible. For example, in order to fix a bug (the “continue reading” feature didn’t work) I had to go to different forums until I finally found out that I need to change code in /wp-content/themes/<my template>/content.php

And that was only one of the tweaks I had to do. If I would start listing all the problems I had, then the most important ones will be:

  • folder permissions problem – prevents you from upload media and plugins to your server (to fix you have to run chown and chmod from linux prompt!)
  • fix .htaccess (because of the same permissions issue) manually in order to add WP additional lines
  • manually set favicon.ico turned out to be a real pain too (edit /wp-content/themes/<my template>/header.php)
  • manually change /wp-content/themes/<my template>/footer.php to NOT display “Proudly powered by…”

But on the bright side:

  • It’s so nice to easily install (after you got over the permissions-issue) plugins like:Sociable and All in One SEO Pack
  • The speed is very good even though I didn’t install a cache-plugin just yet (this is also the place to recommend the CDN services of cloudflare (I use their free package)
  • easy to choose, install and configure a template (but then again, if you’re very meticulous and want to move a certain line one millimeter to the right – get ready to dive into tons of php & css code…)
  • you get to have comments “out of the box”
  • and much more (tags, categories, menus, tons of free plugins etc)

So by all means, if you’re using another CMS for blogging purpose (I had my experience with Joomla, Drupal and Magento store – but I got to admit that I didn’t try blogger) you should re-consider your choice.

I’ll wrap up with the following cute joke:
A programmer tells his friend that yesterday he almost got busted when his wife asked him which one he loves more: her or his computer.
Friend: So, what did you reply ?
Programmer: I said I love her more
Friend: good choice! so, why do you say you almost got busted?
Programmer: cause luckily, she didn’t ask me about my laptop…

Blog renovation

SEO Made Simple – book summary and review

seo

A good friend of mine runs his own company. He always paid 3rd parties to handle his SEO but, as a developer, he felt he should put the effort into learning, at least the basics, so that he could understand if the money he’s spending on these services has a good ROI. So a few days ago he came to me all enthusiastic about this great SEO book. I love learning new stuff, and today, whatever your business is – you have a website, so SEO becomes more and more important. Now, I already read plenty of stuff about search engine optimization (there’s tons of free stuff on the web), but I never really read anything that was structured in a methodical way, well organized and that goes over all the different subjects – I couldn’t resist borrowing (and soon after’ ordering) it!

Relatively, it’s a short book (about 130 pages) but it summaries all the basic principles of SEO, it provides all the “DO’s” and “DON’Ts”. I was already a few pages into the book when a thought came into my mind: why not create a short summary of this book, and add my own “take” during the process. Now you might think, if I already got the summary – why should I buy the book ? well – you really don’t have too (I’m not getting paid any commission :D ), but, bare this in mind and it’s true for any good technical book – you can’t read it once (let along summary) and grasp it, you’ll find yourself going back to the book, again and again, looking up things you read but don’t remember exactly to the small details. And besides, I believe that if someone took the time and effort to write a book, and the outcome is good – he should be rewarded!

After this long intro, let’s get down to business, here it goes:

Meta Tags

TITLE

Keyword/phrases – up to 7 words, can be two phrases separated by “|”

DESCRIPTION

Use your keywords twice (not more!) – do not stuff keywords – it has to be a good description (seems natural) for click-through rate

KEYWORDS

Less important. Do not repeat the same keyword consecutively (i.e. marketing, marketing resources,…) avoid stuffing!

ROBOTS

<meta name=”robots” content=”all”> encourages crawlers to crawl ALL the pages in your website

URLs

FORMATTING

Content first, clean code (http://validator.w3.org), no JS no flash no styling – extract all non-SEO relevant data to external files), heading tags (1-3 is enough), title, alt tags, favicon, proper keywords placement, internal linking (using navigation menus and anchor text) and sitemap.xml. If your site loads fast (pagespeed/YSlow!) – You’ll get extra points with Google, same goes for schema.org

CONTENT FIRST

The location of the content should be “above” the links, if possible, always think about the order in which crawlers scan the page.
A good example to “content first” will be:

1 Header – logo etc.
2 3 Content
4 Menu/links

 

PROPER KEYWORD PLACEMENT

Place your keywords in:

  • meta-tags
  • title
  • headers
  • first 25 words of the page
  • last 25 words of the page
  • bold font (at least once)
  • italic or underline font (at least once)
  • in the footer/ copyright section
  • define the content of your site in general terms
  • identify keywords related to the topic
  • use google keyword tool
  • select 10-30 keywords based on:
    • at least 3000 monthly searches
    • less than 50,000 monthly searches
    • eliminate unnatural phrases
    • commercial intent – conversion of a keyword in the range of (0,1)
    • KEI (keyword effectiveness index) – calculated by the formula [number of monthly searches/number of competing sites] where number of competing sites is the number of results that returns from Google. Rule of thumb: this should be less than 3M.
    • Most important: research the competition!
      • Use wordtracker (free trial)
      • Use FF plugin: SEO quake
      • More relevant tools in the link in the header
      • Find top ranking sites for these keywords and check their SEO (on-page, alexa etc.) look for:
        • Website URL
        • Google PR (don’t compete with sites that have PR6 or more)
        • Number of backlinks – no rule of thumb here
        • Keyword in meta-tags, headers, title, first and last 25 words, bold, italic and underline
        • Use NO MORE than 2-3 keywords per page

Keywords development

 

Off-Page SEO

  • The most important: about 85% of the weight of PR (vs. 15% on-page)
  • Directory & search engines submissions
  • It’s not the number of the backlinks – it’s the quality (PR)
  • It’s not only the quality but also the relevancy of these sites (backlinks)
  • Link types: one-way (best), reciprocal (link exchange/swap/partners), three-way (also good)
  • Build “partner page” with reciprocal links – not more than 100 (link farm). Place a link to this page from your home-page
  • Use “title” in href as well as good anchor text (can be two phrases separate by “|”), rel=”dofollow” and target=”_blank”
  • Link building using articles (1-2 per week)
  • Publish the article on your website first
  • Submit to article directories using spinner (about 25 directories per week)
  • Keep publishing moderately – otherwise google might consider it as SPAM
  • Directory submission: DMOZ, submit only to directories that review manually, reciprocal-links are good as long as the link to your site has higher PR than yours. Use directory submission software – do not SPAM.
  • Register your blog with directories: DMOZGoogleTechnorati.
  • Design your blog for SEO using on-page optimization techniques
  • Add RSS feed (needs to be updated regularly)
  • Update sitemap.xml (needs to be updated regularly)
  • Write weekly posts and submit to ping-o-matic
  • Enter your keywords in the “Name” field
  • Use real email address
  • Use complete URL
  • DO NOT post links in the comment
  • Write a good comment: relevant and at least 3 sentences long.
  • Google: “high PR do follow blogs” to find blogs for comments
  • Follow blogs with high PR so you can comment there from time to time – never comment more than once on the same post
  • Update new content at sites like: deliciousreddit and Digg
  • Add social buttons to your blog, you can use services like AddThis
  • Usually cost money – but it can be done in affordable ways
  • Create content which will be interesting and NEW enough to get picked up by News-sites:
    • Create a poll. A recommended way to do this is in your blog! 100 voters will be enough for first-time, usually 250 voters is a good threshold
    • Use services like surveyMonkey (~$20)
    • Press release distribution services usually cost in the range of $1-250
    • You can use a press release each time you add a new feature to your site
    • PRWeb – good but a bit pricey, PR-Inside and Free press release are more affordable for beginners
    • Find press release which already rank high for your desired keywords
    • Find forums related to your niche with high PR and “live” activity
    • Important: does the forum allows “do follow” links in the signature?
    • Many signatures allow up to 3 links – using 2 is enough
    • Some forums require you posting 10 comments before allowing you to use a signature
    • Use your keywords in the signature wisely
    • If you want to start promoting new keywords and you change your signature – it might affect old comments!
    • Posts/Comments should be relevant, meaningful and valuable
    • The goal is ~10 forums which you’ll regularly post/comment
    • It requires a lot of work! Consider outsourcing it only after you’ve posted at least the first round!

Blogging

  • Register your blog with directories: DMOZGoogleTechnorati.
  • Design your blog for SEO using on-page optimization techniques
  • Add RSS feed (needs to be updated regularly)
  • Update sitemap.xml (needs to be updated regularly)
  • Write weekly posts and submit to ping-o-matic

Blog commenting

  • Enter your keywords in the “Name” field
  • Use real email address
  • Use complete URL
  • DO NOT post links in the comment
  • Write a good comment: relevant and at least 3 sentences long.
  • Google: “high PR do follow blogs” to find blogs for comments
  • Follow blogs with high PR so you can comment there from time to time – never comment more than once on the same post

Social bookmarks

  • Update new content at sites like: deliciousreddit and Digg
  • Add social buttons to your blog, you can use services like AddThis

Press Releases

  • Usually cost money – but it can be done in affordable ways
  • Create content which will be interesting and NEW enough to get picked up by News-sites:
    • Create a poll. A recommended way to do this is in your blog! 100 voters will be enough for first-time, usually 250 voters is a good threshold
    • Use services like surveyMonkey (~$20)
  • Press release distribution services usually cost in the range of $1-250
  • You can use a press release each time you add a new feature to your site
  • PRWeb – good but a bit pricey, PR-Inside and Free press release are more affordable for beginners
  • Find press release which already rank high for your desired keywords

Forum Marketing

  • Find forums related to your niche with high PR and “live” activity
  • Important: does the forum allows “do follow” links in the signature?
  • Many signatures allow up to 3 links – using 2 is enough
  • Some forums require you posting 10 comments before allowing you to use a signature
  • Use your keywords in the signature wisely
  • If you want to start promoting new keywords and you change your signature – it might affect old comments!
  • Posts/Comments should be relevant, meaningful and valuable
  • The goal is ~10 forums which you’ll regularly post/comment
  • It requires a lot of work! Consider outsourcing it only after you’ve posted at least the first round!

Authority links: profile sites

Site in which you create a profile and can use it to comment, mainly forums, wikies, communities and such. There are services like Angela’s links that provide you with monthly high-PR profile sites [alfasin: I’m not sure how good this website is!].

SOCIAL MEDIA SITES

This part deserves a dedicated book, SEO Made Simple doesn’t say much about it, but it does provide rules of thumb: in every major social network (Facebook, Tweeter, Pinterest, Instagram etc.) – create a profile and as part of your profile link back to your website.

Facebook – you can create and promote a fan-page

Tweeter – use tags and lists (hash tags #) to link back and promote your content

YouTube – create a monthly video to promote you site, you can create a dedicated channel, in the beginning of the video description link back to your website and use your keywords

Google places – open an account and keep updating on a monthly basis with pictures and new content

Important:

Beware of fully automated tools! Consider outsourcing specific tasks instead. Recommended sites for outsource: odeskelance and upwardsseo, there are other famous outsource sites like: gurugetafreelancer and 99designs.

 

 


What can I say, Michael Fleischner did a wonderful job!
Now back to programming (to be continued…)

SEO Made Simple – book summary and review

Corona SDK review

CoronaSDK-icon
Two weeks ago I went to Corona SDK Hack Night in Menlo Park. When I went in (8PM sharp) I saw that everybody were already sitting with their laptops turned on, working. “I see that I’m late” I said out loud while unpacking my laptop bag, and got a few hostile looks, it was weird… And then it clicked, these people were not part of the Corona lab group – these were just different groups of students that came, as any other day, to use the free wifi @ Happy Donuts…

I blushed… feeling like a weirdo… but after a second I saw that everyone got their heads back in their laptops so I grabbed a cup of coffee and waited till someone else shows up (at least I wasn’t late…).

Actually, the story starts about a year ago, when I first decided to write an Android app, it was pretty cool: I downloaded and installed Android SDK and the required Eclipse plugin, skipped most of the tutorials and just “went for it”. A few months later I had my app and it was pretty cool, it was provided with song-names from a server that I ran on rackspace and buttons like: “watch on youtube”, “share on facebook” and “buy on amazon” and some other stuff. All the buttons just triggered REST-API calls to the server which implemented all the logic on the backend. It actually worked fine on the simulator and on my HTC Aria, but when tested on higher versions of Android it failed, and it took me a while to figure out why. I found out that from Gingerbread and on – only non-synchronized HTTP calls were supported.

A few months ago, my wife came up with an idea for another app and I promised her that I’ll build it. Then I heard about Corona – so I decided to give it a fair chance. Alas, we started with the wrong foot: A very kind guy named Jerry Pierre helped me by instructing me to download and install Corona SDK first, and then Lua Glider (IDE). I’m a bit ashamed to admit, but the laptop I’m (rarely) using has Vista installed and since the computer is not mine – I can’t install Win7. At home, and at work, I use desktops, and in general – I prefer desktops (yes, I know it’s weird – but I don’t like laptops…).

It seems that Lua work well on Win7 as well as on Mac, but on Vista it took me an hour of fighting until I gave up and opened Notepad++. So after a couple of hours, and a very nice walk-through I got from Mayank Malik – I decided to wrap it up, go back home, and use my desktop to continue “playing” with Corona.

lua

The good:
Someone put a lot of effort in creating this abstracted development environment which compile your code into native code of one of the following operating systems: iOS, Android, Kindle Fire and NOOK – which is very cool. Further, Corona arrives with a respectable built-in library that supports media (video/audio/images) but even more impressive is the physics library which allows you to easily add a gravity to your objects, an example for a way to use it will be the following simple and straight-forward implementation:

local function onTilt( event )
physics.setGravity( 10 * event.xGravity, -10 * event.yGravity )
end

The bad:
* New syntax
* limited functionality
* Can’t combine your own native code with Corona’s
* Once you started using it – you’re tied to it, you won’t be able to migrate to another platform. Ever.

The Ugly:
* The price:
– $199/year for the “indi” version – a license to publish in one of the two: iOS or Android.
– $349 to get the “pro” version – the option to build your app in all the supported platforms.

coronaicon

Now seriously, this price is good if you plan to monetize your apps, but when you just build things for fun, then it’s a bit pricey. If I was planning to develop a game that would use the fancy physics library – I might have chosen Corona, but since I don’t (and also since I don’t appreciate the “closed garden” policy) – I decided to pass.

Update: I just found out that Mayank helped organizing Grinding the rails with Ishan Singh – and since I was planning to learn Ruby anyways, I might just show up there 😉

corona_product_teaser

Corona SDK review

I see dead code (homage for IntelliJ Idea)

intellij-624x120

About a month ago I went with my friend David to Silicon Valley CodeCamp. David met a few friends so we all set together and had lunch during which we discussed a few coding issues but we were also excited about the raffle which was to take place right after lunch. I told them that I’m not interested in the XBOX (which was considered as the best prize) and that what I would really LOVE is to get a license for intelliJ. First time I “met” intelliJ was

Back to our lunch at Silicon Valley CodeCamp. People were hoping to win the XBOX and I told them that I don’t care about the XBOX and that I wish they would throw in intelliJ licenses (one license worth $500). We finished our lunches and went to the main court where the raffle took place, and to my astonishment, the guy with the mic announced the list of prizes and among them, one intelliJ license. I was stunned. David laughed and said: “I’m going to win this one for you”.

And believe it or not – he did!

intellij_idea

A few days later, I’m sitting at my desk, installing the newest version of intelliJ, and it took me only a few seconds to see what I was missing so much…

Jetbrains, the company that made intelliJ had a booth there in SVCC – so I got myself a shirt that says: “I see dead code”. And now I really do: among many other cool features, intelliJ finds unused parameters and colors them in grey. This simple feature is priceless (and I’m not familiar with any equivalent feature in Netbeans/Eclipse).

iseedeadcode

The shirt I got at SVCC

So, at that same first day when I started using intelliJ again, I went over some code, looking for something, and then I run into the following method (two points to the readers that find what’s wrong with this method):

  private String getContractName(Connection conn, int contractOrderId) {

    String methodName = "getContractName";
    PreparedStatement st = null;
    ResultSet rs = null;
    String contractName = null;
    try {
      //get contract name
      String sqlQuery = "SELECT CONTRACT_NAME FROM __CONTRACTS WHERE contract_order_id=?";
      st.setInt(1, contractOrderId);
      rs = st.executeQuery();

      if (rs.next()) {
        contractName = rs.getString("CONTRACT_NAME");
      }
    }
    catch (Exception e) {
      Utils.writeLog(className + ":" + methodName +"- Warning: " + className + ":" + methodName + "-" + e.getMessage(), DEBUG);
    }
    finally {
      Utils.closeConnections(null, st, rs, null);
    }
    return contractName;
  }

Without intelliJ it’s not easy to see it, but if you figured it out – way to go!
Between the following two lines:

String sqlQuery = "SELECT CONTRACT_NAME FROM __CONTRACTS WHERE contract_order_id=?";
st.setInt(1, contractOrderId);

there’s one “little” line missing:

st = conn.prepareStatement(sqlQuery);

This could be easily detected with intelliJ since “Connection conn” passed in the method’s signature was marked grey. Actually, there isn’t only one wrong thing with this method, now that we understand the problem, we can also see that every time this method is being called, an exception is being thrown on:

st.setInt(1, contractOrderId);

and that this exception is caught six lines below – but the only thing that is being done is a “debug” printing to log (not even an error!) and then the method ALWAYS returns null and continues.

How many bad practices do we see here – can you count ?

1. we don’t “fail-fast” (the method should have either thrown an error or at least print ERROR to log instead of DEBUG).
2. we throw and catch an exception (which is costly!) without really handling it.
3. we return a default value which is meaningless
4. I’m 100% sure that no unit-tests, functionality tests, regression, end-to-end or any kind of tests were written and used here – otherwise this bug would have been easily caught.

So here’s a call to all you decision makers, think about the hours of debugging, fixing, reviewing the code-fix, QAing the fix and deploying – that could be saved, not to mention potential damage that could be done to your company and your clients. Always consider purchasing the best tools you can for your engineers. It might look like an “expensive investment” but it’ll pay off, trust me (and if you can’t trust me, you should believe Joel. Check-out item #9 on his list).

I see dead code (homage for IntelliJ Idea)