On Finding The Perfect “Add to Cart” Button

Recently I participated in a code camp at Al-Makinah where we introduce participants to the fundamentals of the front-end component of the web. I was asked to review the model answer to one of the exercises given to the students. It was simple; they take a web page written in HTML, CSS and JavaScript and improve it in a way that shows what they’ve learnt that reflects what they were taught. The exercise addressed several aspects like user experience improvement, semantics, validation of the markup … etc. It was a simple shopping cart with several products cards laid out in a grid.

I spend a lot of time writing HTML. It’s been a part of what I am doing every day for more than a decade. For me, HTML is more than just a few elements that you throw here and there; I invest a lot in picking the elements that I use. While I was reviewing the exercise, I stopped in front of the “Add to Cart” button. It was an <a> tag with a link. I started questioning myself; part of me hates the fact that this is a link not a button inside a form. It makes perfect sense to be a button. Of course it can be made anything. Simply attaching a listener that fires an ajax request updating the cart will work. But it doesn’t feel right. This isn’t semantically correct. Before I decide what the “Add to Cart” element should be, I decided I should write down the criteria addressing how this element should behave given all the possible circumstances.

Criteria:

  1. It must have the same behavior in presence or absence of JavaScript.
  2. If there are other fields like “amount,” pressing enter (submitting the form) should behave like clicking the button.

At this point I was convinced that this should be a submit button not a link. I quickly realized that this will require each product card to have a form tag with more elements like hidden input with product id for example. In big shops, the home page sometimes hosts a lot of product cards. It even uses sliders to save the space for “Newly arrived,” “Hot offers,” “Hot in category X” and the list can go on. A single page can contain more than a hundred of product cards. All this increase the amount of the HTML tags we serve to the user and increase the page size (comparing to serving a single <a> tag per card).

There is also another problem the submit button doesn’t address and it is very common. It’s the products that need you to select attributes before adding it to your cart (like shirt size or color). It’s common that these product cards redirect the user to the full details page of the product asking him to pick the required attributes in order to add the proper item to the cart. Now I changed my mind; I don’t think it’s a problem using a link for this functionality. I decided to change the first rule I mentioned earlier; it shouldn’t have the same behavior. It just should work in a way.

Before discussing the possible scenarios, I want to clarify something before getting into the argument of whether we should support users with no JavaScript or not. I believe both sides of the argument have valid points; however, there are reasons that you don’t want to lose even the smallest fraction of the users without JavaScript. We’re talking about e-commerce where conversion is translated directly into money. The solution is also pretty simple whether you decided to go with progressive enhancement or graceful degradation as you will see later on.

The available scenarios

Using button

If the product can be added directly to the cart, use button inside a form tag. It can use ajax when JavaScript is available or submit to the server directly when it isn’t (embracing progressive enhancement).

Pros:

  • Semantically, it is more accurate.
  • The behavior is similar in presence or absence of JavaScript.

Cons:

 

  • Require more code for form tag and other elements that identify the product.

 

If the product cannot be added without selecting attributes, use an anchor tag linking to the full product details page.

Using link

Use links in all cases. When JavaScript is available, hijack the click event and add the product to the cart using ajax (embracing graceful degradation). If it isn’t, direct the user to the full details page.

Pros:

 

  • Requires less HTML, just a link with data attribute for product id.

 

Cons:

 

  • The experience is different based on the presence or absence of JavaScript.
  • In absence of JavaScript, the link that says “Add to Cart” will do something completely different. It should then say “Show product details.” This might cause confusion for people using assistive technologies like screen readers.

 

How other e-commerce platforms address this issue?

I decided to review how the other popular e-commerce platforms address this issue. At robusta, we have success stories building successful big e-commerce platforms in Egypt using popular platforms like WooCommerce and Magento Enterprise Edition. I picked the popular open source e-commerce platforms available which provided a demo and a default theme. Now, bear in mind that the result of this analysis is highly based on the used theme. If you are using a different theme it is very likely that your theme uses a different markup than what I am about to show you. The default theme is important because developers use it as a boilerplate for their themes. Some platforms like Magento allow defining a parent theme and extend it to override some of its parts instead of writing everything from scratch.

Magento 2

Magento comes with a theme called Luma. It uses a button tag without a form. The button itself has some additional data attributes related to the product. As you might guess, this implementation doesn’t work except when JavaScript is available. It’s worth mentioning that Magento 2 utilizes RequireJS to split JavaScript into modules. Luma theme by default loads 119 JavaScript file in the homepage alone. With Magento, JavaScript bundler merely seems to function properly; there is a big chance for failure at any point (by network timeout, server failure, slow internet connection,…etc.). It’s disappointing to see the e-commerce giant uses an inaccessible solution that only works with JavaScript.

WooCommerce

The number 1 WordPress plugin for e-commerce really shines with its implementation. It uses a link that directs to the current page with the query string “?add-to-cart=id”. When JavaScript is available, the product is added to the cart using ajax. When it’s absent, WooCommerce handles it in a way different than the scenarios I mentioned before. The product is added to the cart and the user is redirected to the same page again with a success message on top. WooCommerce says “Add to cart” and it delivers what it says exactly with no confusion. When the product requires picking attributes, it redirects the user to the product details page.

OpenCart

OpenCart uses a button without a form that has an onclick attribute. It requires JavaScript to work. When JavaScript is available the product is added to the cart. If the product requires selection of attribute the same button redirects the user to the full details page.

VirtueMart

Perhaps this is one of the least known e-commerce platforms but it is well known across Joomla community. VirtueMart uses a classic form with a button. If JavaScript is available, the experience is enhanced with ajax. If not, the form is submitted and the user is redirected to the cart page. If the product requires selection of additional attributes the button is disabled and the options are displayed to pick from inside the cart. VirtueMart embraces progressive enhancement and provides a solution that works smoothly.

osCommerce

This is an obligatory mention to the e-commerce dinosaur. From the minute you check the demo you get the feeling that you stepped back in time into PhpNuke. osCommerce doesn’t include an add to cart button in the listing. Adding the product to the cart is only available inside the full product details.

Conclusion

There are several methods to mark down the “Add to Cart” button. We should always embrace a method that guarantees the button will work then improve the experience using JavaScript.

Action Cable: Rails 5 Most Anticipated Features

Being a tech agency, we at robusta deal with a lot of apps with different kinds of business logic. From simple e-commerce apps to complex full-featured social networks. So being able to communicate with users is a vital feature that we have to incorporate in almost every project. We were looking for a simple solution to create chat modules in Rails apps. That was when we decided to give Action Cable a shot in one of our projects.

Action Cable

Action Cable is a simple framework that introduces WebSocket support to Rails apps. It provides a server-side as well as a client-side integration with WebSocket. DHH made a quick tutorial and a preview of Action Cable on his YouTube Channel.

WebSocket

WebSocket is a two-way TCP-based protocol. It works by opening a persistent connection between the server and the client. Both sides can use the connection for data exchange.

Drawbacks

When we decided to try ActionCable and WebSocket, we have looked for the
points where WebSocket falls behind. The main concern (still a small concern though) is that WebSocket is a relatively new protocol. Thus, older browsers lack WebSocket support. Thus, not all web browsers support WebSockets.

WebSocket Vs. Other Solutions

In our research, we had to find out the differences between WebSokcet and other solutions. Here’s a quick comparison between WebSocket and other well-known solutions.

AJAX

WebSocket protocol differs from HTTP known methods (Ajax or Polling) where the client (the browser) does not need to make a request for the data it needs to fetch.
In AJAX, the client sends a request to the server and gets an instant response from the server then the connection is closed as most HTTP requests.

Polling

Server polling resembles AJAX except that the connection is kept alive for some time until it times out and gets closed. The client requests for a new connection with the server again after a defined time.

WebRTC

WebRTC is different from the previous methods in the way the data is transmitted. In WebRTC, the data is exchanged between clients (no servers involved). On the other hand, WebSocket data exchange happens between a client and a server.

A Use Case

Here we will build a simple app to demonstrate the abilities of Action Cable. The app is somewhat similar to a Twitter replica. The app will have three main features: tweeting, messaging, and showing the online presence of registered users.

Setting up the app

We start by installing the latest version of Rails. As of this time, the latest version of Rails is 5.0.0.rc2. An important note before trying to install the latest version of Rails is that it requires Ruby 2.2.2+ to run. $ gem install rails -v 5.0.0.rc2. We then create a new app without a test framework using $ rails new TwitterCable -T --database=mysql. Now we need to create the database $ bundle exec rake db:create. Next step is writing code for our app.

Authenticating users

We setup devise for user authentication. We do that by adding gem 'devise' to the Gemfile and calling $ bundle install. Then we use Devise’s generator to install it. $ rails generate devise:install and $ rails generate devise User to create our user model. Last step is to migrate the database $ bundle exec rake db:migrate

The tweeting module

To keep our app as simple as possible, we’ll add only two attributes to our Tweet model $ rails g model Tweet content:string user_id:integer. Now we open Tweet model and add the association with User model.

  # app/models/tweet.rb
  class Tweet < ApplicationRecord
    belongs_to :user
  end

Now we need to setup the controller and the views:

  # app/controllers/tweets_controller.rb
  def index
    @tweets = Tweet.all.order("created_at DESC")
  end

  def create
    @tweet = current_user.tweets.create! tweet_params

    redirect_to tweets_path
  end

  private

  def tweet_params
    params.require(:tweet).permit(:content)
  end
  # config/routes.rb
  resources :tweets, only: [:index, :create]
  <!-- app/views/index.html.erb -->
  <div class="text-center">
    <h3>Recent Tweets</h3>
  </div>
  <br>
  <% if current_user %>
    <%= form_for Tweet.new do |f|%>
      <%= f.text_area :content, placeholder: 'New Tweet' %>
      <div class="right">
        <%= f.submit 'Add Tweet', class: 'button' %>
      </div>
    <% end %>
  <% end %>
  <br>
  <div class="text-center">
    <div id="tweets">
      <%= render @tweets %>
    </div>
  </div>
  <!--app/views/tweets/_tweet.html.erb -->
  <% cache tweet do %>
    <div class="tweet">
      <div class="callout">
        <h5><%= tweet.user.email %></h5>
        <p>
          <%= tweet.content %>
        </p>
      </div>
    </div>
  <% end %>

It’s time to try the app. In your browser, open localhost:3000/tweets. This is where we can create new tweets and each time we we will get redirected to the tweets index page.

Up until now, everything is normal as we would’ve seen in any CRUD application but things will change a bit when we start using Action Cable to handle rendering new tweets.

We can use Rails generator to create a new channel for our tweets $ rails g channel Tweet. This creates two new files app/channels/tweet_channel.rb and app/assets/javascripts/channels/tweet.js. The first file handles the connection on the server side while the other handles the client-side connections.

We have to mount Action Cable server in our routes file so that Action Cable can listen to WebSocket requests:

# config/routes.rb
mount ActionCable.server => '/cable'

# app/channels/tweet_channel.rb
...
def subscribed
  stream_from "tweet_channel"
end
...

We will use Coffeescript for its Ruby-like syntax and our convenience. Rename app/assets/javascripts/channels/tweet.js to tweet.coffee and add the following code to the file.

# app/assets/javascripts/channels/tweet.coffee
App.twitter = App.cable.subscriptions.create "TweetChannel",
  received: (data) ->
    $('#tweets').prepend data['tweet']
    $('[data-behavior~=tweet_field]').val('')
  # Called when there's incoming data on the websocket for this channel

We then modify the form by adding remote: true to prevent Rails from redirecting after submission.

<!-- app/views/index.html.erb -->
...
  <%= form_for Tweet.new, remote: true do |f|%>
  <% end %>
...

And we inform the controller to broadcast the new tweet html to the TweetChannel in the create action.

# app/controllers/tweets_controller.rb
...
def create
  @tweet = current_user.tweets.create! tweet_params
  ActionCable.server.broadcast "twitter_channel", tweet: render_tweet(@tweet)
  head :ok
end

private
...
def render_tweet tweet
  render(partial: 'tweets/tweet', locals: { tweet: tweet })
end

Now we try again to create a new tweet; the tweet will be immediately appended to the DOM of the tweets index page.

The messaging module

We start now by adding our models and filling them with methods and scopes that we will need in the next steps.

$ rails g model Conversation sender_id:integer:index recipient_id:integer:index
$ rails g model Message body:text conversation_id:integer:index user_id:integer:index

Check the
conversation model and the
message model on Github.

Next we add
conversations controller
and messages controller and we set up our
routes.

We also need to add our view templates and partials for conversations and messages controllers.
Check conversation views
and message views on Github.

The trick in the messages module is that we want to stream and subscribe to message channel based on the conversation id (a conversation is between two users).

We use Rails generator to create a new channel for our messages $ rails g channel Message. This creates two new files app/channels/message_channel.rb and app/assets/javascripts/channels/message.js. The first file handles the connection on the server-side while the other handles the client-side connections.

On the server side, we subscribe to message_channel_#{conversation_id}, so that each connection between any two users will be unique.

# app/channels/message_channel.rb
...
def subscribed
  stream_from "message_channel_#{params[:conversation_id]}"
end
...

On the client side, we will use Coffeescript for its Ruby-like syntax and our convenience. Rename app/assets/javascripts/channels/message.js to message.coffee and add the following code:

# app/assets/javascripts/channels/message.coffee
$ ->
  window.conversation_id = $('#conversation_id').attr('value')

    App.message = App.cable.subscriptions.create { channel: "MessageChannel", conversation_id: conversation_id },

      received: (data) ->
        $('#messages_' + conversation_id).append data['message']
        $('[data-behavior~=new_message_field]').val('')
      # Called when there's incoming data on the websocket for this channel

Here we set a global variable conversation_id whose value is obtained from the
DOM and passed in the params object to the MessageChannel on the server-side.
The received function is called when there is data sent from the server to
the client side. This is where we append the new message to messages_conversation_id
element in the conversations show template.

Here, we find the messages_conversation_id element which we append new messages to.

<!-- app/views/conversations/show.html.erb -->
...
<%= content_tag :div, id: "messages_#{@conversation.id}"  do %>
  <%= render @conversation.messages, conversation: @conversation %>
<% end %>
...

Inside the form, we add a hidden field that holds the current conversation_id
so that the client side of the message channel can send it to the
server-side channel.
Note that we add remote: true to prevent Rails from redirecting after the form submission.

  <!-- app/views/conversations/show.html.erb -->
  ...
  <%= form_for [@conversation, Message.new], remote: true do |f|%>
    <%= f.text_area :body, placeholder: 'New Nessage', 'data-behavior' => 'new_message_field' %>
    <%= f.hidden_field :conversation_id, value: params[:id], id: 'conversation_id' %>
    <%= f.submit 'Send', class: 'button' %>
  <% end %>

The difference in messages controller is that we broadcast our newly created
message to Action Cable server using the conversation_id of that message.

# app/controllers/messages_controller.rb
...
def create
  @message = @conversation.messages.create message_params
  ActionCable.server.broadcast "message_channel_#{@conversation.id}", message: render_message(@message)
end

private

def render_message(message)
  render(partial: 'messages/message', locals: { message: message })
end
...

The online presence module

In this part, we will show the currently logged-in users inside the conversations index page so when we click on any user, we could chat with them directly.
The different part here is that we need Redis to store our logged-in users because, in Action Cable, each page refresh is counted as a new subscription. Thus, each time a user refreshes the web page, a duplicate entry will be created for that user in the online users list.

We will setup Redis by uncommenting redis gem in the Gemfile. And then we will add an initializer file for Redis so we can use it in any part of our application.

# Gemfile
gem 'redis', '~> 3.0'

# config/initializers/redis.rb
$redis = Redis.new(:host => '0.0.0.0', :port => 6379)

We will use Redis sets to store the id of each subscribed user and to remove the ids of unsubscribed users. Then we will rerender the partial responsible for listing the logged-in users.

We start by generating a new channel $ rails g channel OnlineUsers and adding the code responsible for storing or removing user ids from Redis set and rendering the online_users partial.

# app/channels/online_users_channel.rb
class OnlineUsersChannel > ApplicationCable::Channel
  def subscribed
    stream_from "online_users_channel"
    $redis.sadd 'online', current_user.id
    ActionCable.server.broadcast "online_users_channel", users_html: render_online_users
  end

  def unsubscribed
    $redis.srem 'online', current_user.id
    ActionCable.server.broadcast "online_users_channel", users_html: render_online_users
  end

  private

  def render_online_users
    ApplicationController.renderer.render(partial: 'users/online_users')
  end
end

On the client-side part, we use jQuery to set the html() attribute of #onlineUsers element to the html received from the server-side channel that contains the newly rendered online_users partial.

# app/assets/channels/online_users.cofee
App.online_users = App.cable.subscriptions.create "OnlineUsersChannel",
  received: (data) ->
    $('#onlineUsers').html(data['users_html'])

We add _online_users partial under users views. Inside the partial, we loop thought our Redis set online and fetch each user.

Online Users

In conversations index page, we render the partial inside the #onlineUsers element.

  <!-- app/views/conversations/index.html.erb -->
  ...
  <div id="onlineUsers">
    <%= render partial: 'users/online_users'%>
  </div>
  ...

You can check the full source code on Robusta’s Github account.

Conlusion

Action Cable is an easy and simple solution to use. It introduces a fully integrated suite that works well with Ruby on Rails on both client and server sides. To use WebSockets or not is dependent on the use case.

Resources

Real-Time Rails: Implementing WebSockets in Rails 5 with Action Cable
WebSockets, caution required!
http://stackoverflow.com/questions/10028770/in-what-situations-would-ajax-long-short-polling-be-preferred-over-html5-websock

Magento 2 vs Magento 1: A Comparison and Review (Part 2)

In part 1, we started a comparison between Magento 2 and Magento 1 in order to list what’s new in Magento 2, while comparing it to Magento 1 to put things into perspective.

We compared themes and extensions development, frontend development, and admin dashboard.In this sequel, we will explore more into the features, performance, stability, and deployment process.

Features

Magento 2 has all the features included in Magento 1, yet adds upon it many new features like:

  • CSS Preprocessing
  • Better Security
  • PayPal integration enhancements
  • More payment methods based on BrainTree
  • Full-Page Cache (FPC), now available for Community edition as well.
  • Performance, or lackthereof as we will discuss later.

Magento 2 is not an upgrade from Magento 1; it is more of a re-write so while it introduces some new features, more effort is put into Magento’s Core as we inspected earlier, so the lack of impressive new features is justified as long as no features were removed and hopefully with time new features will be added after stabilizing the product.

Performance

Releasing a re-write version of a software without adding new features is justifiable and actually expected for the first couple of releases until bugs are squashed and everything is stabilized.

However, releasing a new version of a software like Magento 2 with clear performance issues, where performance has been/is a crucial cornerstone of the software, is never acceptable and is a clear sign that the maturity of the software is badly affected.

Although the different articles list performance enhancements as a feature of Magento 2, we do realize from the experience of working with both Magento products that this is not true and, most probably, this is all just theoretical speculations.

It takes only seconds after installing Magento 2 to realize the following:

  • Magento 2 is more CPU hungry than Magento 1.
  • Magento 2 requires more housekeeping than Magento 1
  • Running Magento 2 in “developer” mode, which is essential during development phase, means you have to wait minutes between page loads, and you won’t even be able to spend that time doing something else as Magento will make sure to leave no resources whatsoever for your computer to be able to perform other actions in parallel.
  • Magento 2 is slow, like really slow, unbearably slow, not even comparable to Magento 1; we expected Magento 2 to be at least on par with Magento 1; however, this is not true, performance is much worse and pages load much slower and use much more resources.
  • Even in “developer” mode, which should mean that all caching is turned off, Magento 2 still utilizes some caching mechanisms to be able to perform in an acceptable manner. You have to run `setup:static-content:deploy` to deploy static content like assets, and Magento automatically caches “Dependency Injection” in var/di directory, which causes frustrations and slows down development.

These disappointments were confirmed by the various benchmarks published by other developers, as well as comments by the developers on the different forums.

Almost all benchmarks indicated that while Magento 2 uses more CPU resources than Magento 1, it is also twice as slow as Magento 1, meaning that it can serve only half the number of requests that Magento 1 can serve in the same time, all while using more CPU resources.

These benchmarks were confirmed even with caching turned on, so while Magento 2 offers Full-Page Cache (FPC) for both enterprise and community editions (Magento 1 offered FPC only for enterprise edition), and also offers integration with Varnish out-of-the-box, it is still slower even when utilizing the different caching techniques.

A detailed benchmark can be found at https://www.magecore.com/blog/news/magento-ce-1-9-vs-magento-ce-2-0-performance-comparison “Magento CE 1.9 vs Magento CE 2.0 Performance Comparison”, written by “Dima Soroka” who is the former lead Architect of the Magento project and wrote on the official blog for “MageCore” who are certified Magento Partners.

While Magento 2 supports PHP7 which normally reduces processing time by almost 50%, Magento 2 is still slower than Magento 1; however, utilizing PHP7 makes Magento 2 a bit faster and decreases the gap between Magento 2 and Magento 1.

Here is a detailed benchmark by Dima Soroka as well, https://www.magecore.com/blog/news/php-7-affects-performance-magento-1-9-ce-vs-magento-2-0-ce “How Does PHP 7 Affects Performance of Magento 1.9 CE vs. Magento 2.0 CE”

Magento 2 tries to offer better performance by offering the following tools, which while helping a lot it also adds a lot to the complexity:

  • Compiling of PHP files.
  • Merging of global assets
  • Indexing
  • Full-Page Cache
  • Caching of “Dependency Injection”
  • Caching various other items like configurations and layout

We hope that Magento team will focus on optimizing performance so that Magento 2 at least matches the performance of Magento 1 in the near future.

Stability

It is expected that a major software like Magento doesn’t go live unless bugs are squashed and proper testing is conducted; unfortunately, this was not the case in our experience.

A quick visit to Magento 2 code repository on GitHub at https://github.com/magento/magento2 reveals the amount of issues opened. We have also faced many issues ourselves although we have always used the latest stable release of Magento 2.

Some issues were critical, like the issues affecting the cache and the translations, others we have attempted to make temporary fixes for ourselves, but all in all, our developers have always been surprised by the bad quality of the code in areas with bugs.

Have a look at the release notes for the latest version of Magento 2.1 at http://devdocs.magento.com/guides/v2.1/release-notes/ReleaseNotes2.1.0EE.html. Notice the amount of issues fixed and the known issues not fixed yet. This is obviously not an enterprise-edition software.

It is worth-mentioning that upgrading from Magento to version 2.1 was a complete failure for us; we even had to roll back to a backup of version 2.0.7 after 48 hours of downtime and different trials to fix Magento issues ourselves.

One issue was with the default Magento theme, which we built upon a customized theme. Here is an answer from Stack OverFlow pointing out the bug in the theme “Luma”, along with comments by developers who suffer from Magento 2 instability.

image04

Deployment Process

In today’s software development world, deployment should be fully automated; it is no longer accepted to have a person dedicated to deployments, or even downtime caused by deploying a newer version of a software.

Continuous Integration (CI) and Continuous Deployment (CD) aim at decreasing the effort and time required to push new features, enhancements, and fixes by the developers to production servers by automating the process.

Different softwares and frameworks are built with CI and CD in mind; tools and scripts are developed to make sure deployments are safe, automated, and fast.

We have easily established an automated deployment process for Magento 1 on production servers; the process simplified is the following:

  1. Push release to code repository.
  2. Automatically trigger a script on production servers.
  3. Pull the updated files.
  4. Run modman to make sure new files are correctly linked.
  5. Clear the cache.

What’s beautiful about this process is, beside the simplicity, it takes couple of minutes and doesn’t cause downtimes, unless the code itself caused issues which should be detected by CI when running the automated tests.

We tried to devise a similar process for Magento 2, after many iterations we figured out a long process that looks something along the lines of:

  1. Push release to code repository.
  2. Automatically trigger a script on production servers.
  3. Run `composer update` to update the different packages and since we built our extensions as composer packages which will be updated as well and this usually takes a couple of minutes.
  4. Run `setup:upgrade`; this upgrades the extensions and run any install/upgrade scripts that alter the database and/or install new extensions; this usually takes a minute.
  5. Delete some directories from the directory “var”
  6. Run `setup:di:compile`, this generates DI configuration files, which usually takes 5 minutes and can fail and cause a lot of trouble.
  7. Clear everything inside the directory pub/static.
  8. Run `setup:static-content:deploy`, which creates and deploys static content and assets for all themes, and for all locales, usually takes a whopping 20~30 minutes, shouldn’t fail but actually failed miserably when upgrading Magento to version 2.1.
  9. Re-Indexing.
  10. Flushing the cache.

The process is complicated, long and prone to failure. It causes downtime and takes on average 45 minutes.

This is definitely an unacceptable downtime; the process is overly complicated due to different caching and caching-like mechanisms like DI configuration and static-content deployment.

Conclusion

Magento 2 is definitely a great effort towards matching modern PHP frameworks, which we touched upon in different aspects and have always praised during day-to-day development.

However, Magento 2 team has a lot of challenges to tackle if they aim at staying the number 1 e-commerce solution, using and applying modern standards and technologies is an advantage; however, stability and performance are killers if not given proper focus.

At the end, we hope to see practical improvements during the coming months so as to restore our confidence in Magento being our go-to solution for e-commerce platforms which require scaling, performance, and integrations with the different systems.

Magento 2 vs Magento 1: A Comparison and Review (Part 1)

Magento is an open-source e-commerce platform written in PHP. The software was originally developed by Varien Inc., but after witnessing huge successes eBay started investing in Magento by buying shares and eventually acquired Varien.

In late 2015, Magento 2.0 was released, almost completely rewritten using modern programming concepts and technologies, we will be discussing the changes in Magento 2.0 and the new features through comparing it to Magento 1.

Extension & Theme Development

Magento 2 uses modern approaches in how it is built and how developers can build extensions and themes for it.

In Magento 1, themes and extensions’ files were distributed in many locations, we had to use a Module Manager “modman” which allows developers to place the files in 1 folder and then let modman create symlinks “shortcuts” to where Magento expects the files to be placed; this allows for better and easier development and also allows for using Code Version Control systems like “git”.

Magento 2 on the other hand uses modern approach; everything is a Composer package, which allows for better organization, updating, and code maintenance, along with automating some of the scripts and commands that need to be run after any updates.

In our current project with B.TECH, we made use of that fact and based all our work (both extensions and theme) on Composer packages, linked to our code repository to allow for instant code deployment (Continuous Deployment) for both staging and production servers.

This is definitely a step forward towards modern development cycle, and one that puts Magento 2 inline with modern PHP frameworks while opening new opportunities by enabling direct use of any of the thousands of packages available using Composer Packagist.

Frontend Development

Magento 1 uses Prototype JavaScript framework because -believe it or not- jQuery was not production-ready when Magento was in vitro, and it kept depending mainly on Prototype and the framework’s add-ons like Scriptaculous.

This made frontend development for Magento 1 a bit hard, although you can easily inject jQuery, sometimes you just need to stick with Prototype and work with it, which is not a pleasant experience usually.

Magento 2, on the other hand, uses modern approaches; it uses jQuery and Knockout, but more importantly, it uses RequireJS, which makes a webpage load only the required libraries instead of loading everything in all pages.

Magento 1 -and 2- has options for merging JS files, which, while reducing the number of HTTP requests, makes loading a huge JS file required with every page load, This was a valid recommendation in the early days;however, things have changed with HTTP 2.

HTTP 1.1 used to open a new connection for every HTTP request, so merging assets was a must; however, this has changed with HTTP 2 which allows for parallel requests on the same connection. This allows faster assets download and invalidates the recommendation for having less requests per page.

RequireJS is a good candidate for making better use of HTTP 2, as it makes use of HTTP 2 parallel requests per connection, while loading only required libraries per page, a win-win situation.

Our Senior Frontend Developer, Ahmed Alfy, wrote a nice introduction to RequireJS; make sure to check it out here.

Admin Dashboard

Magento 1 had a very clear dashboard; you can easily navigate and access everything; it loads fast and extensions can easily add functionalities to it.

Magento 2 revamped the dashboard completely. It is based on AngularJS, along with RequireJS for loading the assets, which, while sounds like a step towards utilizing modern technologies, raises many flags.

Magento 2’s dashboard is criticized due to the following.

  • It can easily fail to load if any of the assets didn’t load for any reason.
  • It is also much slower, due to having to wait for all the assets to load.
  • While using AngularJS sound promising, it is actually a disadvantage as it makes loading a large number of products or orders -or any relatively long list- very slow, and very CPU demanding, which can even cause the whole browser or computer to freeze for seconds or indefinitely sometimes.
  • It is built on AngularJS version 1, although version 2 is now out of beta.
  • While the overall look of the dashboard is modern and the use of icons and large menus should make it more usable and friendly, this is actually not the case as it is harder to navigate through all the menus and the different menu options and submenus.
  • While it is easy for extensions to add menu items, installing many extensions -which is normal- can easily make the dashboard’s menu much harder to use or not really usable at all.

Here is a quick example showing the steps required to reach the “Cache Management” page, which is a frequently visited page.

Magento 1

image02

 

  1. Hover over the “System” link in the horizontal menu.
  2. Click on “Cache Management” in the vertical submenu.

Magento 2

image03

image00

image01

  1. Look for the “System” menu item in the vertical (sidebar menu).FYI you won’t be able to see it as extensions add menu items that push Magento’s menu items downwards.
  2. Scroll down till the icon for “System” menu item is visible.
  3. Click on it.
  4. Inspect the submenu that slides, you won’t find the “Cache Management” link.
  5. Scroll up till you see the link for “Cache Management”.
  6. Click on it.

This is just an example of how the navigation, while might look seemingly better, is actually confusing and hard.

We have touched upon important aspects of the comparison and saw the advancements in Magento 2 in many areas. While it looks like Magento 2 is a real improvement upon Magento 1, in the second part of this blog post we will see comparison of performance and performance-related changes in Magento 2, we will also discuss the stability of Magento 2, so here is a sneak peak.

image04

Customizing Sublime Text Editor for Faster Development

Welcome back to our second episode discussing Sublime Text Editor and how you can customize it depending on your preferences.

Sublime Interface

Blue Light Effect

Given our job as programmers, we keep staring at the screen more than 8 hours per day. The constant exposure to the screen’s bright (blue) light hurts the human eyes including some symptoms:

  • Slightly blurry vision
  • Difficulty focusing
  • Your eyes feel dry, irritated or tired
  • Headache
  • May cause permanent eye damage

Due to the previous reasons, I recommend using light text on dark background with huge contrast to increase focus, reading speed and avoid any eye strain symptoms.

Sublime Theme

Currently I am using a dark theme for Sublime called Seti_UI, you could download it easily from the package control panel as previously mentioned in our last episode and type in Seti_UI and then install it as mentioned in the User Preferences section by adding "theme": "Seti.sublime-theme",. You can customize the theme by using the theme options from the Seti_UI package documentation. You can see an example of the theme in Figure 1.

Set UI Theme
Figure 1: Set UI Theme

Syntax Highlighting

As for the code syntax highlighting, I am using a syntax color scheme called Brogrammer (yes with a B not a P 😀 ), where the the syntax provides large contrast between the light (white) text and dark (black) contrast. It was ranked one of the best themes of the year 2014 as mentioned in several posts including The Best Sublime Text 3 Themes of 2014. As shown in Figure 2, also, the bright red color of the keywords enhances the code readability, in addition to the highlighting the String in greenish color.

Brogrammer Syntax Highlighting
Figure 2: Brogrammer Syntax Highlighting

Development Preferences

Now for the coding part itself ;), as most of my development is using Ruby on Rails, I am using the setting of translating all the tabs into spaces and one tab press is equivalent to 2 spaces according to the Ruby and Rails community Style guides. For HAML, I am also using 2 spaces tab for correct indentation of the code fragments to evade any indentation error as HAML is sensitive to spaces. In addition, following the convention of adding an extra empty line and the end of each file on save is facilitated through a global configuration, and removing any trailing spaces in any line across the opened file on save is done automatically.

User Preferences File

Based on my personal experience and after loads of research and customizations, I am going to share my own personal user preferences file. Starting from Sublime text version 3, the users won’t be able to edit the already shipped sublime preferences; however, they can override them in their user preferences to avoid any loss of customization when upgrading sublime.
You can always check your customized user preferences by navigating to your top menu bar on OSX:

  1. Click on Sublime Text next to the Apple menu
  2. Hover on Preferences and choose Settings - User
  3. You will view all your preferences as a JSON object as follows
     {   //Theme customization 
         "theme": "Seti.sublime-theme",
         "Seti_SB_bright": true,
         "Seti_bold_slctdfile_labels": true,
         "Seti_no_scroll_icons": true,
         "Seti_orange_button": true,
         "Seti_orange_label": true,
         "Seti_pad_3": true,
         "Seti_sb_tree_miny": true,
         "Seti_tabs_small": true,
         "itg_sidebar_tree_small": true,
         "itg_small_tabs": true,
    
         //Code highlighting scheme
         "color_scheme": "Packages/Theme - Brogrammer/brogrammer.tmTheme",
    
         //Spell Checker use English-GB dictionary
         "dictionary": "Packages/Language - English/en_GB.dic",
    
         //Crucial Development Preferences 
         "ensure_newline_at_eof_on_save": true,
         "indent_guide_options":
         [
             "draw_normal",
             "draw_active"
         ],
         "tab_size": 2,
         "translate_tabs_to_spaces": true
    
         // General UI customization
         "font_options":
         [
             "no_round"
         ],
         "font_size": 14.7,
         "ignored_packages":
         [
             "Vintage"
         ],
    
         //Modified Sublime Interaction
         "overlay_scroll_bars": "enabled",
         "preview_on_click": true,
         "highlight_line": true,
         "highlight_modified_tabs": true,
     }
    
  4. After editing your preferences, click CMD\CRTL + s to save.
  5. In the optimal cases, you can restart sublime in order to make sure that all the configurations are loaded for the new theme and color scheme to take effect. Otherwise, the configurations are loaded after saving the preferences.

By reaching this point, we conclude the series of customizing Sublime Text Editor for faster development.

Top 10 Reasons Why We Quit Social Media

Now that we’re in Ramadan, the prime time for advertising, media and communication, it reminded me of why we’ve come to consciously and intentionally shut down our social media operations only a little bit less than 1 year ago. Back then, we had an amazing team of creatives and a bunch of notable accounts yet we still decided to cut it off and, since then, chatting with other agencies about social media only feels relieving and reassuring.

but-why-meme-generator-social-media-why-1a8b62

I feel socially obliged to share it with my fellow entrepreneurs out there to either save them precious years of their lives or inspire them to come up with their own recipe of success.

We’re not so impulsive here at robusta nor do we follow the crowd. We have exhausted all analysis before finally deciding social media is not for us. Here are 10 reasons why.

gwed-lad-free

  1. Barriers… What barriers? I can’t see no barriers!

Everybody knows that a market with a high entry barrier for competition is a market that’s more secure and sustainable and as the barrier becomes lower it quickly becomes a red ocean where only the lower price wins. In the social media ground, your grandma can start her own social media agency, today, right from her comfy couch, and compete with you tomorrow on that Culinary Workshops account. No?

Peter_Griffin_And_The_Chicken

  1. Fresh Blood.. You’re Bloody

Now that everyone already knows there’s a social media agency around every corner and a social media freelancer in every family, you become easy to replace. Clients will always feel empowered, tempted and encouraged to ditch you and try something new. Even if you’ve done a good job, at some point it’s always time for fresh blood. Your agency will probably exhaust its creative concepts for the client in the first couple of campaigns and just as you’re recharging your creative energies for the next campaign, your client will seek out to other agencies knocking their door to listen to new pitches, lower prices and once this starts they will find every reason to ditch you and find their next prey.

flat,800x800,075,t.u1

  1. Pricing

Social media account management market prices are somewhere between EGP 4K to EGP 12K for at least 80% of local accounts. This should supposedly pay for team’s salaries (designers, copywriters, community managers, creatives, media and account manager), indirect salaries to keep your agency running and expenses such as your rent & utilities and make a worth-it-enough profit. That’s probably one reason why agency owners turn out to be so mean to their people, pay them peanuts, delay their salaries or even skip it at all or they reach out to deep pockets to finance the show and keep their star accounts alive and rocking, despite losing.

wolf-of-wall-street

 

  1. It’s not really social media, it’s a game of PR

Social media on its own is really not an offering; however, PR is. If you’re into PR with its different practices from Events to Press to Media Relations etc… social media can be an essential complementary service. If you’re only doing social media, you’re as good as gone.

great_gatsby

 

  1. You’re either friends with the “influencers” or you’re screwed

In a country like Egypt, social media is driven by shepherds, commonly known as social media influencers. They would tell the people what to like, what to eat and where to go, and you’re either friends with them (you can buy it at $9.99 in low seasons and as high as $99,999 in higher seasons) or you can struggle to speak in the vacuum

57761423

  1. Ads

Your agency is being paid peanuts that can’t even cover your costs and then your competitors come up with that creative pitch and bottom low pricing. How can they do that? Ads. Most of the agencies lose on their social media fees and make “profits” out of the ads business. Ads, being a slightly more technically involved business, are almost not audited by the clients. But even that has a price war to the extent that you find agencies claiming to run ads for 5% management fees aka out of a 100K campaign over 3 months (which is a relatively well-funded campaign), they charge 5K which is less than 2K a month. WTF? 2K to finance the ads manager, designs, optimization, reporting and account management? You guys are either losing or you’re just taking a cut out of the 100K behind the client’s back and poor clients barely understand 20% of what the agency wants them to understand about their ads.

d53a9d9b6f54131c6a6ee24690ee64fcccda2946372a331428d20d42ce0e31f9

  1. Social Media is not steroids, say that to your client!

Clients expect social media campaign today – tomorrow I’m the most popular on Facebook or nothing. Clients want to have their say on the design, the copy writing, posting frequency & posting times and on the claim of company policy and then you’re held accountable for results.

They expect every post to be a campaign on its own. While it’s understood that every now and then a campaign to shake things up is a nice thing but it’s just unfair to expect. They compare a post to a TV commercial that takes shit loads of money, time & team to produce and has a lifetime that could extend anywhere between 1 to 6 months. They expect a post to drive sales, directly, all the time.Moreover, clients don’t want to spend enough on ads to make social media work and they’re not even educated about the difference between a social media post and the lifetime of a post.

yY6dWUy

  1. Payments & Cash flow

Knowing how contracts work around Egypt, a wise agency needs to have its own collection strategy that keep its cash flow near healthy and know for sure this has to be a mixture of relations, politics, red eye and knowing where and when to stop the tap. With social media, you have to keep the show running for the account day in and day out if you want to stay in it. Regardless of your payments status, you have to always be a giver and your client will almost always find a reason to delay your payments, and poor you having to keep their show running regardless or just lose it at all.

Big change begins with small steps

  1. The illusion of growth

80% if not more of the social media agencies are either unethical in the ways they make money (see: ads) or they’re chasing after the illusion that they’re now incurring losses to build their portfolio and once they strike the right balance, they’re on the way to endless profits. This is just bullshit.

4454454

  1. You don’t really have a strategy & the model is immature

You need to be joker of all trades.. and yes you will be master of none. The game between a company’s marketing team, creative agency and production agency is just not that mature, yet.

Few last words…

We see it as an integral part of the communication and requires lots of customer service and alignment on day in & day out business operations so better done in house. If you want to survive you need to focus on the niche. It’s collaborative team work. It will not work without a PR who takes care of events coverage.

If you want to survive you need to do it 1. a-la-a call center style, 2. creatively and find your niche (like Kijami) and 3. complement it with a powerful barrier (own your own media channels like MO4).

We told you what’s going wrong with social media. Here’s a list of social media agencies worth considering who’re good at what they do and can tell you what’s good about it.

  • Unplugged: Good, passionate & ethical people
  • Mental Media: Young and progressive
  • MO4: Dirty as the media game can get. F&B and Nightlife freaks
  • Kijami: Truly grabbing the essence of social media
  • Nineteen84 Management: I had to have a list of 5 because 4 seems to be odd

Sublime Text Editor Packages in Daily Development Tasks

In this article, we are going to discuss how the usage of Sublime text editor packages affects your development tasks. Many of us can write code on any text editor either pre-shipped with the operating system or downloaded from the Internet. We will begin by comparing the common text editors available nowadays; then we will explain how to install them and provide a list of the most popular packages and how to use them in your coding experience. Finally, we will discuss how the usage of Sublime text editor packages affects the daily development tasks of programmers.

Sublime Text Editor vs. RubyMine IDE

The most well-known editors or IDEs in ruby on rails development are TextMate, Sublime Text and RubyMine. This table demonstrates a comparison between Sublime Text Editor and RubyMine IDE (as TextMate product was discontinued):

Criteria Sublime Text RubyMine
Customizable YES PARTIALLY
Fuzzy Search YES NO
External Plugins YES (open source) LIMITED (JetBrains sources)
Booting Time Negligible (< 2s) Significant (> 30s)
Key Bindings Customizable Predefined sets
In-app Terminal Not present Built-in
Code Lint YES (External sources) Built-in
Notifications Not present Built-in
Price Free, License License only
Free OR USD $70 once and for all USD $ 199.00 /1st year, $ 159.00 /2nd year, $ 119.00 /3rd year onwards

Verdict:

We chose to use Sublime Text Editor for being highly customizable and because it provides the ability of fuzzy search where you type fragments of a folder and file name and it will suggest the best matching file lists. A significant number of external (3rd party) libraries or extensions to sublime can be installed to tailor it to your development needs.

Sublime Text
Sublime Text

Last but not least, it’s FREE version without any missing features 🙂

What Are Sublime Text Packages and What Are The Most Popular Ones

We will now discuss an overview on Sublime text packages and how to install them on your system.

Sublime text packages are external extensions for the text editor to add multiple features, themes and code style schemes and extend the default editor to cope with the developers needs and ease their life.

How to Install Sublime Package Control

In order to install the package control for Sublime, you need to do the following.

  1. Open the console of Sublime Text itself by clicking on CMD +`
  2. Then copy and paste the following:
     import urllib.request,os,hashlib;
     h = '2915d1851351e5ee549c20394736b442' + '8bc59f460fa1548d1514676163dafc88';pf = 'Package Control.sublime-package';ipp = sublime.installed_packages_path();urllib.request.install_opener( urllib.request.build_opener( urllib.request.ProxyHandler()) );by = urllib.request.urlopen( 'http://packagecontrol.io/' + pf.replace(' ', '%20')).read();dh = hashlib.sha256(by).hexdigest();print('Error validating download (got %s instead of %s), please try manual install' % (dh, h)) if dh != h else open(os.path.join( ipp, pf), 'wb' ).write(by)   
    
  3. Restart sublime and viola! You can now install packages to your editor.

Here, we will discuss a number of sublime development packages that are used by most of the team members. The packages are categorized into several categories.

  • Category 1: Some packages that you need to install right away after installing Sublime.
  • Category 2: General Web Packages
  • Category 3: Specific Ruby on Rails packages.

Development packages you need to have

Here is a list of the need-to-have packages that will ease your development progress:

Packages Name Usage
BracketHighlighter provides the ability of highlighting the start and end of a code block
Clipboard Manager provides the ability of Copy & pasting many items and retrieve them from the generated copy and paste stack
Color Highlighter provides a color preview of with the color codes either rgba or hex next to the line number, mostly used in .(s)css files
ColorPicker provides advanced color picker either predefined colors, hex or rgba color codes
Emmet provides the ability of writing faster HTML codes using some snippets and abbreviations e.g. div.text-center > p.bold
Git provides the ability of extensive git control from sublime diff, blame, commit, etc…
GitGutter-edge highlights edited line numbers that were changed from the last commit in symbols
Gitignore provides gitignore templates predefined in a remote github repository to be used in your projects
Indent XML prettifies XML code syntax and indents it to increase readability
Local History enables local version control for files using timestamps
Pretty YAML indents YAML files for better readability
SideBarEnhancements provides more control on a project folder from inside of sublime editor e.g. new file, folder, renaming, etc…
Sublime-Text-2-BIDI a package to write bi-directional text in sublime, used mainly for RTL languages such as Arabic.
SublimeLinter lints many programming languages for errors such as ruby, java, etc…
TrailingSpaces removes trailsing spaces in any file, and it is better to be set to trim after save.

Web Packages

Packages Name Usage
Autoprefixer adds cross-browser CSS prefixes for a certain number of properties to ensure that all the properties behave the same across all modern web browsers
Bootstrap 3 Snippets provides most of Bootstrap styles as snippets to used directly in your code files
CSS Extended Completions provides CSS competitions for most, maybe all CSS properties and predefined values
jQuery provides autocompletion for JQuery functions and a brief description about the usage of each.

Ruby and Ruby on Rails packages

Packages Name Usage
Alignment eases the alignment of ruby syntax according to the style guide lines where all the = are aligned to the same column
BetterCoffeeScript adds CoffeeScript support to sublime including code completions and highlighting
Cucumber adds cucumber support for sublime including Gherkin syntax
Cucumber Step Finder eases the ability to search in cucumber Gherkin steps for navigation in all cucumber steps files
ERB Autocomplete eases the addition of ruby on rails HTMl templating language ERB to autocomplete the <%= %> tags
Haml adds the support of RubyHaml package to Sublime and speeds up the development with HAML using autocomplete and block comments
HTML2Haml converts HTML code to HAMl either whole file, selection or clipboard copied code.
SCSS provides better support for SASS (.scss) files in sublime editor

Impact on Development

The usage of Sublime packages has a significant positive impact on development tasks where it can do the following.

  • Increase the speed of developments
  • Ensure following of conventions and style guides for many programming languages
  • Ease the development flow with keyboard navigation without the use of a mouse/trackpad
  • Enter distraction-free environment of coding away from any notifications, emails or anything

After knowing why we chose sublime text, how to install external packages and what are the most popular packages used.

In the next episode, we will talk about configuring sublime text editor and some of the previously mentioned packages to facilitate your development life.

Introduction to RequireJS (Part 1)

RequireJS defines itself as a file and module loader. The first part is easy to understand; it can be used to load files but what about loading a module? What are modules anyway? Modules are containers encapsulating a piece of code that performs a particular function. A module should also have an interface that lets you access its functionality in a uniform manner.

Why should you care about modules?

Splitting an application into a group of modules is similar to dividing a book into chapters and sections. It makes it easier to read and find the parts you need. Writing modules at the beginning might seem like a lot of work and sometimes developers get confused and ask themselves “Do I really need to do this?” When your application grows, you start to appreciate the time you invested in decoupling your code and writing reusable modules that interact with each other.

What are the benefits of using modules?

Perhaps the greatest benefit of using modules is code reusability. Modules can be imported anywhere in an application to perform its task whenever it is needed without having to worry about duplicating the code. It also becomes easier to export a module to be able to use it in a different project because it is encapsulated. Generally speaking, it facilitates maintenance and readability of the code as well as making it more manageable and easier to test.

How I entered the world of modules loading

From my experience, I used to include all my scripts each in a separate script tag. It doesn’t matter how many scripts I am loading; they will be executed in the same order they are written. There isn’t any abstraction or anything that will add complexity, so why would I need a library to do what I can already do? My build process was taken care of concatenating and uglifying my files so what’s the problem with loading a single nice file?

I wasn’t convinced until I read a couple of discussions and a few questions began to arise in my mind especially when projects I work grew larger as follows:

  • Most of the plugins and the codes I write aren’t required to run on every page. Why would I load something huge like a WYSIWYG editor on a dashboard while the user won’t really need it at the moment?
  • Most of the time, it was difficult to debug something without checking many files to find where exactly is that function defined.

I decided to give RequireJS a try. To be honest, I fell in love with the sense of power it gave me with the conditional loading of the scripts I define. Errors became much easier to debug. I no longer have to care about the loading order of my scripts–things just work out themselves magically. I got rid of the serving-one-fat-file anti-pattern with the rise of HTTP/2. What I do now is ship small files that can be transferred in parallel. Focusing on splitting my code into modules helped me improve the work.

I started to see things from another perspective and, after using it for a while, I really had a hard time imagining developing anything without it. We will explore how to start using RequireJS in the upcoming article. See you soon!

A Better Way for Obtaining Best Sellers in Magento

Best Sellers, New Arrivals, and Promotions are three cornerstones of any ecommerce solution; they add great value for both customers and store owners.

Best sellers offer customers quick view over the products that other customers buy the most, which adds to the customer’s confidence when deciding to make a purchase and makes it easier for the customer to choose between alternatives.

The method of calculating best sellers is pretty straightforward; you count how many times has each product been sold and order the result by summed-up quantity ordered; then you’ve got yourself a best-sellers widget or products slider that should most probably be placed on the homepage.

In development mode, and on staging server as well, everything is working as you expected, until you move to production and the store owners decide to launch huge campaign that will drive thousands of visitors to the homepage; everything falls apart then, as each request makes Magento recalculate the best sellers and then load every product to show the product’s card.

Caching to the rescue, you tell yourself, and it helps relieve the stress off your database and your store comes back online. You could then make a change and try to refresh the cache while the visitors are hammering the homepage with requests looking for your store’s best selling products and that is exactly when you realize that even those split seconds of recreating the cache can become minutes of downtime as the requests keep hitting Magento while it is recreating the cache are all cache-miss that hammer the database directly until Magento gets it act together and starts serving content from the cache again.

Now let’s back off a moment, Magento has some powerful reports, one of which is, guess what, “Best Selling Products”! So why don’t we check how does Magento generate such report without bringing online stores to their knees, meanwhile, applying one of the most known software engineering principles in the process, which is DRY (Don’t Repeat Yourself) while we’re at it. Okay?!

Magento doesn’t generate this report on the fly or, to be specific, it doesn’t calculate best sellers on the fly; however, it makes use of it’s own cron jobs to aggregate best selling products every day and save them in a database table for later use. This allows Magento to directly hit this pre-calculated table of best sellers and just do the work of getting every product’s attributes, while sacrificing the ability to get fresh and up-to-date list of best sellers, which is not that crucial in most cases.

So let’s stand on the shoulders of giants and make use of that pre-calculated, automatically-aggregated table of best sellers we say, and instead of calculating the best selling products for every request, just query this table for the period you wish and then fetch the attributes you want to view for each product.

As a rule of thumb in Magento development, make sure to invest some time checking if the feature you want to develop/implement is already implemented in a way or another in Magento; this will save you so much time and effort on the long run and will also, most probably, give you a better idea for doing things. Have you encountered a similar problem while using Magento? Tell us what you did in the comments.

To Infinity and Beyond

 

Arguably, one of the movies’ most famous catchwords, and despite the fact that my number 1 early-morning activity with my 3-year-old has recently been watching and reciting Toy Story at 7am on a weekend with one eye open and the other half-asleep, this post plays to a more serious note about an organization’s own journey of self-exploration…

2015 was a particularly interesting year for robusta particularly because, for a change, we rethought our strategy, structure and, believe it or not, our robustivity vision, too!

Lots of concerns have triggered such exercise. It was mostly about the pursuit of profitability, sustainability, scalability and where we see robusta in 5 years from now. It was quite regular of a discussion between the managing partners to question the scalability of robusta and if it’s ever a candidate for exceptional growth that fulfills ours and the team’s aspirations for humongous growth. Don’t get me wrong! robusta was doing quite well already but we’ve always seen robusta not as a boutique agency but rather a flagship empire and been questioning a lot the way to get there.

Inspired by Gallup’s Strengths Finder and our IGNITE Development Program designed and implemented by our good friends at Mirqah ( more on this in upcoming episodes), we decided to start our pursuit by identifying and playing to our organizational strengths.

Cutting a long story of several client meetings (more of disguised interviews), internal workshops and self-reflections, it was becoming clearer that our top 3 strengths were our solid development skills and portfolio, a strong and influential culture fueled by an exceptionally competent team and robusta’s brand equity, reputation and reach within diverse verticals. Our weaknesses have always been lack of clarity to what we aspire to become that translated into stretching ourselves too thin across several streams which eventually lead to subpar profitability.

Building on this understanding, we made some bold decisions of exiting some of our service offerings and accounts. We’ve completely abandoned Branding, Social Media, Microsoft-based technologies, and trivial/low potential tickets. The reasons why we stopped each are quite interesting and each deserves a blog post on its own. We naturally decided to focus on our leading services which are E-Commerce, Mobile, Websites and Web Apps.

We also turned around our perspective looking at our team and decided to get rid of the illusion of growth that comes with growing our headcount after figuring out this is, in most cases, nothing but a sign of lack of efficiency. Comes next naturally is an overpowering need to look after productivity and a sharply pruned work force that makes it easier to invest in our culture & human capital development.

Ironically, we’ve also figured out that there’s such a HUGE local market that we need to dominate first before crawling beyond borders. Last but not least, we’ve done what turned out to be a pretty good job standardizing and innovating our retainer-based project development/support packages.

The said resolutions automatically put us on track with total clarity on how to go about restructuring the organization to achieve what became our solid vision.

“To serve as a flagship of national economy and become one of the top listed EGX companies by 2030”

This also fits perfectly with our designated 4-fold mission towards our clients, our people, shareholders and the community.

Finally, what we’ve mostly learned the hard way is that although focus seems to be an obvious strategic recommendation for any organization, it takes a lot of wisdom and learning about your customers, competitors, team and, of course, yourself to really be able to tell what focus means and how it applies to your organization.