Showing posts with label web-development. Show all posts
Showing posts with label web-development. Show all posts

Saturday, September 28, 2019

Review of Shopify - from a developer's point of view

I setup this online shop over a couple of weekends - Chow Slow - Slow Feeder Dog Bowls. After launch I continued to make various improvements and optimisations to the presentation and content of the site. Since launch three months ago, the online shop has so far taken 72 orders.

The eCommerce SaaS product Shopify was used to build the site, on the Basic Shopify (monthly) plan.

Here below are my opinions on Shopify:

Shopify - Good points

  • Many payment options - I chose the Shopify Payments option. It accepts Apple Pay and Google Pay when on a mobile browser for example. You can tell that Shopify have extensive experience with taking payments - everything is really polished.
  • Test mode works well for putting through test credit card orders and seeing the customer experience end to end. Can also password protect the site while its under development.
  • The free themes are good and can be customised for most online shops. I used the free "Minimal" theme and then customised the layout of the home page, added several pages and added a blog.
  • Great optimisations and layouts which work well on mobile. More than 60% of the traffic for the site comes from a smartphone browser as opposed to a traditional desktop browser.
  • Really useful "Timeline" admin feature on the customer and order admin pages - see all the interactions that have happened with a customer in a simple timeline display, with a timestamp shown on each interaction.
  • Excellent "Conversion Summary" admin feature - see the site behaviour of your customer from when they first visited your site to when they bought something.
  • Comprehensive "Fraud Analysis" admin feature - for orders paid by Credit Card - recommendation of whether the transaction is likely fraudulent or not: probability shown as low, medium, or high.
  • Ability for customers to sign up with either their mobile phone number or email address. Shopify automatically sends communications to the customer using either mobile SMS or by email.
  • Easy to add social media accounts, which then automatically appear on the site footer.
  • Products are easy to configure and easy to change in terms of page title and content.
  • Ability to edit raw HTML in most places.
  • Easy to setup a custom domain, with TLS/SSL included (which just works).
  • There are SEO optimisations and settings available at a page level. You can change the page title, meta description and URL.
  • Integration with Google Analytics is excellent - the 'Advanced eCommerce' option should be turned on - it results in a data going straight into GA for your conversions and sales.
  • Page load time is good - bulk of the home page loads typically in 2-3 seconds.
  • A comprehensive API for writing custom integrations with other backend software and systems.
Shopify - Bad points
  • Marketing integrations - Facebook Ads for example - difficult and error prone to setup. Facebook Ads never worked for me after many headaches trying to setup. The marketing integrations seem like a quick way to lose money fast.
  • Inability to structure the Products, Pages and Blog sections to be within a custom sub-folders structure (as is typically recommended to silo a website for SEO purposes).
  • Checkout page customization is limited to Shopify Plus users.
  • Checkout script editor is limited to Shopify Plus, so any custom logic to apply discounts has to be done through plugins.
  • API is rate limited - will be fine for most users however ERP systems which run via batch processing or via polling may have issues. You need to implement everything as event driven webhooks rather than by polling the Shopify API.
Shopify - Areas for improvement
  • I'm not convinced of the need for many of the Shopify apps (plug-ins) that get automatically suggested. I have a feeling that they will result in bigger page sizes and slower load times. I have not needed to use any apps yet.
  • Its sometimes hard to find the relevant place for a setting - whether under preferences of the online shop or under settings of the account itself. I should probably make more use of the search bar at the top for this in the future.
Shopify - Conclusion

I highly recommend Shopify for setting up an online shop. When launching, your focus will be taken up with gaining your first customers, online marketing and the delivery process, so having a solid full featured website behind you is crucial.




A bit more about our online shop - Chow Slow - Slow Feeder Dog Bowls

I setup the site for my wife, who runs the business day to day. She handles the processing of orders and deliveries. We came up with the idea of selling to this niche market after finding out about this type of product in 2018. Our pet beagle (Ripley) had an issue of regular regurgitation due to eating too quickly. The slow feeder bowl product solved his problem and results in more relaxed meal times every day.



Follow @dodgy_coder

Saturday, January 2, 2016

Custom domain for Azure Web Apps using FreeDNS

The below steps go through setting up a custom domain name on your Azure Web App, using the FreeDNS service from NameCheap. Both the www subdomain www.yourdomainhere.com and the naked yourdomainhere.com will be setup.

I have an Azure S1 Small Instance App Service Plan on which I'm running 4 web apps. Originally I had planned to use Azure DNS, to keep everything within the same cloud service, but after some initial attempts formed the opinion that Azure DNS isn't mature enough yet to host production web sites. Azure DNS can currently only be administered from within Azure Powershell - that in itself was enough to put me off using it. If you need to make a quick change to a DNS record, you don't want to be having to run Powershell to do it. Microsoft are working on adding Azure DNS to the Azure Portal, but at the moment it's not available.

I have a couple of domains through NameCheap and for those and a couple of others (with CrazyDomains) I decided to use NameCheap's DNS service.  Even when your domain is not registered through NameCheap, they still offer a free DNS service, called FreeDNS.

Note that in the below steps, yourwebappname and yourdomainhere.com should of course be replaced with your specific names.


Step 1. Reduce the TTLs to 5 minutes

Note: you only need to perform this step if you're porting from an existing DNS provider. No need to do this if you're setting up a new web app on a new domain.

Within your current DNS service, setup all the TTL settings (Time To Live) on the DNS records to the minimum (typically 300 seconds, or 5 minutes). This may help in having the DNS changes propagate faster.

After this is done, try to get a full DNS zone file listing. When you port the DNS records to FreeDNS it will help ensure that you don't miss anything. My previous VPS and DNS provider was Linode and I was porting a few web apps from Linode over to Azure web apps.


Step 2. Ensure your Azure web app is running

Ensure your web app is published and running ok at http://yourwebappname.azurewebsites.net


Step 3. Find the IPv4 address of your Azure web app

From a windows cmd.exe prompt ...

C:\> nslookup yourwebappname.azurewebsites.net

Server:  UnKnown
Address:  192.168.1.1

Non-authoritative answer:
Name:    waws-prod-xxx-xxx.cloudapp.net
Address:  1.2.3.4
Aliases: 
yourwebappname.azurewebsites.net
          waws-prod-xxx-xxx.vip.azurewebsites.windows.net


The nslookup command will provide you with your web app's IPv4 address. This is shown in the second Address field above, e.g. 1.2.3.4. I am running an Azure S1 Small Instance App Service Plan. I believe this method still applies to other plans including shared instance plans.

Note that if your web app is restarted or stopped this may result in it being assigned a different IP address. Be aware of this when using naked domain URLs (without the www prefix) since these rely on the A record being configured for the correct IP address of your web app (as per step 6).


Step 4. Setup FreeDNS

On the NameCheap FreeDNS page, enter yourdomainhere.com and click 'Get DNS'. If its eligible, then click 'Add to Cart', then click 'Set up DNS'.

You get this message from NameCheap :-

N.B. don't go ahead and set the nameservers just yet, that step will come later.

    yourdomainhere.com
    Congratulations! Your domain/ sub-domain is added to our DNS service.
    Please set the nameservers of your domain/ sub-domain to

        freedns1.registrar-servers.com
        freedns2.registrar-servers.com
        freedns3.registrar-servers.com
        freedns4.registrar-servers.com
        freedns5.registrar-servers.com

    Our system will periodically monitor your domain's DNS setting and will activate your domain once it is pointing to our servers.

   

Step 5. Verify ownership of your domain

In NameCheap, on the Domain List page, once the yourdomainhere.com is listed as active, then need to click on "Authorize DNS" link...

Select the required email, such as admin@yourdomainhere.com to use as the auth email.

On the domain page, the redirect domain setting will show "Your FreeDNS domain is waiting for Authorization or Verification by domain owner."

In the received email, click on the embedded hyperlink and then on the webpage, click the "I AUTHORIZE" hyperlink.

A message should display "Host has been successfully activated".


Step 6. Setup the FreeDNS records

At this step you'll setup all of the DNS records for your domain.
For all of these I left them with the default TTL setting of 'Automatic'.
In NameCheap, on the Domain List page, click the MANAGE button next to your domain, then click on the Advanced DNS tab.

In the Host records, add the A record with the IP that was returned in step 3.

Type  Host  Value            TTL
A     @     1.2.3.4          Automatic


Add any required TXT records (often used for verification).

Add the 3 CNAME records required to verify ownership of the domain to Azure.

1. Set HOST to awverify
    Set Target to awverify.yourwebappname.azurewebsites.net

2. Set HOST to awverify.www
    Set Target to awverify.yourwebappname.azurewebsites.net

3. Set HOST to www
    Set Target to yourwebappname.azurewebsites.net
  
If required, set the mail setting to Custom MX and add the MX server records...
For example if you have Gmail enabled on the domain you'd use these MX records...

Set Mail to Custom MX

Host        Type Priority      Mail server name
@            MX     20         ALT1.ASPMX.L.GOOGLE.COM.
@            MX     10         ASPMX.L.GOOGLE.COM.
@            MX     20         ALT2.ASPMX.L.GOOGLE.COM.
@            MX     30         ASPMX2.GOOGLEMAIL.COM.
@            MX     30         ASPMX3.GOOGLEMAIL.COM.

  
  
Step 7. Change the DNS nameservers using your registrar

For the case when your registrar is not NameCheap, you'll need to point the nameservers for the domain to the FreeDNS nameservers.

Log into your registrar's website and set the following nameservers, removing the existing nameservers if required ...

        freedns1.registrar-servers.com
        freedns2.registrar-servers.com
        freedns3.registrar-servers.com
        freedns4.registrar-servers.com
        freedns5.registrar-servers.com



Step 8. Wait for the DNS nameserver change to propagate

You can check whether the changes have propagated yet using nslookup from the windows command line ...

C:\> nslookup yourdomainhere.com
C:\> nslookup www.
yourdomainhere.com
C:\> nslookup awverify.
yourdomainhere.com
C:\> nslookup awverify.www.
yourdomainhere.com

Use nslookup in interactive mode for MX and TXT record lookups ...


C:\> nslookup

set q=mx

yourdomainhere.com

set q=txt

yourdomainhere.com

exit


Or you can also use these great online tools for checking the DNS propagation ...

    http://www.whatsmydns.net
    https://www.ultratools.com/tools/dnsLookup

Or on Linux I believe the command is: dig yourdomainhere.com

   
Step 9. Bring the domains into your web app using the Azure Portal

In the Azure portal, go to yourwebappname Web App -> Settings -> Custom Domains and SSL -> Bring External Domains

Enter yourdomainhere.com into the field, and then press tab. Wait for it to verify your CNAME records.

In the next field, enter www.yourdomainhere.com and press tab again. Wait for it to verify your CNAME records.

It should succeed as you tab out of each field, and after you click the save button at the top, it should report "Updating hostname bindings".


Step 10. Test in a browser

Open both www.yourdomainhere.com and yourdomainhere.com in a browser and confirm that they load ok.

Turn on the browser's web developer tools (Network tab) to check that all the components of the web app are loading with HTTP 200 OK status, and are resolving to the new IP address.

Its normal to experience some issues for the first several hours after changing nameservers, for example you may see the domain resolve to the old name server settings or flipping back and forth from new to old. Usually this will settle down after a few hours. It can be caused by the browser caching DNS results, something I've noticed particularly bad in Firefox sometimes. You may also need to flush the DNS cache on the computer you are using.


Flush the DNS cache in windows via:

C:\> ipconfig /flushdns


Other references ...

There is some additional Azure related information in the below post about this subject:
https://azure.microsoft.com/en-us/documentation/articles/web-sites-custom-domain-name/



Follow @dodgy_coder


Subscribe to posts via RSS

Sunday, December 13, 2015

Low cost airlines online pricing hacks

Low cost airlines are the masters of dynamic pricing, bundling and pricing psychology.

Every customer who makes an online booking presents them with some new data to plug into their dynamic pricing algorithm. They also analyse the best way to present the various upgrades available to purchase before the final checkout, to maximise the customer's spend.

I've just taken a look at budget carrier JetStar's booking experience and its use of various pricing techniques and psychology.

After you've searched and selected your flights you'll be presented with a choice. Look at how unattractive they make the "Starter fare" default option ...


The "Plus bundle" at $106 is the one JetStar wants you to pick. The "Max bundle" at $753.49 is just there as an anchor price, to give you the impression that the middle one is good value. The "Starter fare" is the one they want you to avoid. They do this through the selective use of negative and positive language and the colours of grey, green and blue.

The Starter fare

Comfortable leather seat
This is patronising ... is there so little going for this bundle option that they have to mention that you actually get a seat, as opposed to standing in the aisle?

7kg carry on baggage
Strict size and weight limits apply

Negative tone. 7kg is not enough for most people's needs.

Checked baggage not included
Repeated, negative tone.

Starter fares are non-refundable
Negative tone.

... compare this to the most popular option, the option JetStar wants you to choose ...

The Plus bundle

No change fees
Positive.

2,225 Qantas points
Free money. Only $30 credit off your next fare, but its better than nothing.

Free standard seat selection
The power of free.

Meal
More included stuff.

20kg checked baggage
Notice they don't mention that a strict size and weight limit also applies to the 20kg baggage.


People are scared of change fees

Most people when seeing the starter fare option will get the impression that if they need to change their flight for any reason, perhaps due to a flight delay, they are in trouble. In fact, JetStar covers you for flight delays and will make the necessary arrangements and additional bookings free of charge. But they only mention this in the fine print.

Most people want checked baggage

You also get the impression that you have to choose the plus bundle or max bundle if you want checked baggage. Actually, you can choose the starter fare, and then later on in the process you can optionally pay for only the specific amount of checked baggage that you need, at a rate of $46 for 15kg, $50 for 20kg and $62 for 25kg. Most customers likely don't know that these cheaper options are available, and will just choose the plus bundle, paying $106, when all they needed was checked baggage. You can select the Starter fare, then pay separately for 20kg checked baggage ($50), a meal ($15) and a reserved seat ($6) and the total will be just $71, a saving of $35 on the Plus bundle.

Noone wants to be randomly assigned a seat

When it comes to selecting a seat, its a bit disingenuous for JetStar to claim this ...

"You have not selected a seat. If you do not wish to pre-select a seat one will be assigned for you randomly from what is still available at check-in."

When you check in at many airports, assuming you get to the airport early and the plane isn't sold out, you'll still be able to select what type of seat you want - the check-in staff are usually more than helpful and should be able to provide your choice of a window or an aisle seat.

If you're a family with children, the airline will try to assign an adult family member to be sitting close to each child in your family, even when you didn't pay to reserve a seat. If you can't be accommodated at the point of check in, you would likely be able to work something out after boarding by speaking to the cabin crew.

Also, remember this inconspicuous bit of writing at the bottom ...

"Jetstar will attempt to accommodate your seat preference, however due to operational considerations cannot guarantee that your seat allocation will be as your selected preference."

So in other words, they ask you to pay for a seat preference, but cannot guarantee it.


Follow @dodgy_coder

Subscribe to posts via RSS

Saturday, August 31, 2013

Evil User Interface Design

Thanks to Harry Brignull from Dark Patterns for bringing up the interesting topic of evil user interfaces; UIs designed to trick you into spending more money, or buying a product you don't want. Here's the best example from their slidedeck - the Ryanair booking form. I've added some explanatory comments below each screenshot.

1. Ryanair home page.
Loads of sale fares for just £5, looks great ... lets buy a ticket ...


2. The booking form.
Looks straightforward so far, no issues yet.


3. Passenger details section.
Notice the default option for the insurance dropdown is "Please select a country of residence".
If you're not paying attention, you'll assume it is just an address question, and so you'll select your country of residence. In doing so, you are actually selecting to pay for travel insurance ... its designed to trick you into selecting it by mistake.


4. Travel insurance dropdown.
 If you don't want travel insurance, then you have to select the correct option, "No Travel Insurance",
which is listed between Latvia and Lithuania.


5. On error, the dropdown clears your selection.
If you make a mistake anywhere on the form, such as shown above, forgetting to select "Yes" or "No" for the priority boarding question, then when you try and submit it, the insurance dropdown will default back to its original option, which was "Please select a country of residence". They really want you to pay for travel insurance, and this is their last chance of getting an extra few percent of users to buy it.


Follow @dodgy_coder

Subscribe to posts via RSS

Monday, April 9, 2012

Scalability lessons from Google, YouTube, Twitter, Amazon, eBay, Facebook and Instagram


I've gathered together in one place a few lessons in scalability from seven of the most highly trafficked websites around. I've grabbed this primarily from various articles on the excellent High Scalability Blog and have summarized the main points from each company below.

Here are some common ideas I've noticed across all seven companies ...

  1. Keep it simple - complexity will come naturally over time.
  2. Automate everything, including failure recovery.
  3. Iterate your solutions - be prepared to throw away a working component when you want to scale it up to the next level.
  4. Use the right tool for the job, but don't be afraid to roll your own solution.
  5. Use caching, where appropriate.
  6. Know when to favor data consistency over data availability, and vice versa.


Google

Reliable storage
Reliable scalable storage is a core need of any application. The Google File System (GFS) is Google's core storage platform - its a large distributed log structured file system into which they throw a lot of data. Why did they build it instead of using something off the shelf? Because they control everything about it, and it's the platform that distinguishes them from everyone else. From GFS, they gain: high reliability across data centers, scalability to thousands of network nodes, huge read/write bandwidth, support for large blocks of data which are gigabytes in size and an efficient distribution of operations across nodes to reduce bottlenecks.

Infrastructure as a competitive advantage
Google can roll out new internet services faster, cheaper, and at scale at few others can compete with. Many companies take a completely different approach by treating infrastructure as an expense. Each group will use completely different technologies and there will be little planning and commonality of how to build systems.

Build applications on top of a platform
An under appreciated advantage of a platform approach is that junior developers can quickly and confidently create robust applications. If every project needs to create the same distributed infrastructure you'll quickly run into difficulty because the people who know how to do this are relatively rare. Synergy isn't always crap. By making all parts of a system work together an improvement in one helps them all. Improve the file system and everyone benefits immediately and transparently. If every project uses a different file system then there's no continual incremental improvement across the entire stack.

Automation and recovery
Build self-managing systems that work without having to take the system down. This allows you to more easily rebalance resources across servers, add more capacity dynamically, bring machines off line, and gracefully handle upgrades.

Create a Darwinian infrastructure
Perform a time consuming (CPU bound) operation in parallel and take the winner. This is especially useful when you have spare CPU capacity but limited IO.

Don't ignore the Academy
Academia has a lot of good ideas that don't get translated into production environments. Most of what Google has done has prior art, just not prior large scale deployment.

Consider data compression
Compression is a good option when you have a lot of CPU to throw around and limited IO.


YouTube

Keep it simple
Look for the simplest thing that will address the problem space. There are lots of complex problems, but the first solution doesn’t need to be complicated. The complexity will come naturally over time. Choose the simplest solution possible with the loosest guarantees that are practical. The reason you want all these things is you need flexibility to solve problems. The minute you over specify something you paint yourself into a corner. You aren’t going to make those guarantees. Your problem becomes automatically more complex when you try and make guarantees - you leave yourself no way out.

Cheat: know how to fake data
The fastest function call is the one that doesn’t happen. When you have a consistently increasing counter, like a view count, you would need to do a database call every update. Or you could do a call every once in awhile, and update by a random amount in between - people will believe it’s real. Know how to fake data.

Jitter: add entropy back into your system
If your system doesn’t jitter then you get thundering herds of people all requesting the same resource at the same time. For a popular video, they cache things as best they can. The most popular video they might cache for 24 hours. If everything expires at the same time, then every machine will calculate the expiration at the same time. This creates a thundering herd. By jittering you are saying randomly expire between 18-30 hours. That prevents things from happening at the same time and spreads requests out over a long period of time.

Approximate correctness
The state of the system is that which the user sees. If a user can’t tell a part of the system is skewing and inconsistent, then it’s not. If you write a comment and someone loads the page at the same time, they might not get it for half a second, the user who is just reading the page won’t care. The writer of the comment will care though, so you make sure the user who wrote the comment will see it immediately. This allows you to cheat a little bit. When it comes to comments, your system doesn’t have to have globally consistent transactions. That would be super expensive and overkill. Comments are not financial transaction - know when you can cheat.


Twitter

Implement an API
Twitter's API Traffic is ten times that of Twitter’s Website alone. The API is the most important thing Twitter did to grow their user base. Keeping the service simple allowed developers to build on top of their infrastructure and come up with app ideas that are way better than Twitter could come up with. You can never do all the work your user's can do and you probably won't be as creative. So open up your application and make it as easy as possible for others to integrate your application with theirs.

Use what you know
Twitter uses messaging a lot. Producers produce messages, which are queued, and then are distributed to consumers. Twitter's main functionality is to act as a messaging bridge between different formats (SMS, web, IM, etc). Send a message to invalidate a friend's cache in the background instead of doing it all individually, synchronously. Twitter developers were most familiar with Ruby, so they moved from DRb to Starling, a distributed queue written in Ruby. Distributed queues were made to survive system crashes by writing them to disk. In Twitter's experience, most performance improvements come not from the choice of language, but from an application's design.

Know when and what to cache
For example, getting your friends status is complicated. There are security and other issues. So rather than doing a database query, a friend's status is updated in cache instead. It never touches the database. 90% of requests are API requests. So they don't do any page caching for the front-end. Twitter pages are so time sensitive it doesn't do any good. Twitter only caches API requests.

Defend yourself against abuse
Understand how people will try to bust your system. Put in reasonable limits and detection mechanisms to protect your system from being killed by bots. Build tools to detect abuse so you can pinpoint when and where they are happening. Be ruthless. Delete them as users.


Amazon

Use SOA
Amazon's architecture is loosely coupled and built around services. A service-oriented architecture (SOA) gave them the isolation that would allow building many software components rapidly and independently of each other, allowing fast time to market. The application that renders the Amazon.com Web pages is one such application server. So are the applications that serve the Web-services interface, the customer service application, and the seller interface.

Open up your system with APIs and you'll create an ecosystem around your application. Organizing around services gives you agility - you can now do things in parallel is because the output of everything is a service. Prohibit direct database access by clients. This means you can make you service scale and be more reliable without involving your clients. This is much like Google's ability to independently distribute improvements in their stack to the benefit of all applications.

Know when to favour consistency over availability and vice versa
To scale you have to partition, so you are left with choosing either high consistency or high availability for a particular system. You must find the right overlap of availability and consistency. Choose a specific approach based on the needs of the service. For the checkout process you always want to honor requests to add items to a shopping cart because it's revenue producing. In this case you choose high availability. Errors are hidden from the customer and sorted out later. When a customer submits an order you favor consistency because several services (credit card processing, shipping and handling, reporting) are simultaneously accessing the data and each rely on their data to be consistent.

Embrace failure
Take it for granted stuff fails, that's reality, embrace it. For example, go more with a fast reboot and fast recover approach. With a decent spread of data and services you might get close to 100%. Create a self-healing, self-organizing, lights-out type operation.

Only use what you need
Keep things simple by making sure there are no hidden requirements and hidden dependencies in the design. Cut technology to the minimum you need to solve the problem you have. It doesn't help the company to create artificial and unneeded layers of complexity. Not stuck with one particular approach or technology stack. Some places they use jboss/java, but they use only servlets, not the rest of the J2EE stack. C++ is uses to process requests. Perl/Mason is used to build content.

Base decisions on customer feedback
Use measurement and objective debate to separate the good from the bad. Expose real customers to a choice and see which one works best and to make decisions based on those tests. This is done with techniques like A/B testing and Web Analytics. If you have a question about what you should do - code it up, let people use it, and see which alternative gives you the results you want.

Scalability as a competitive advantage
Infrastructure for Amazon, like for Google, is a huge competitive advantage. They can build very complex applications out of primitive services that are by themselves relatively simple. They can scale their operation independently, maintain unparalleled system availability, and introduce new services quickly without the need for massive reconfiguration.


eBay

Partition everything
If you can't split it, you can't scale it. Split everything into manageable chunks by function and data.

Asynchrony everywhere
Connect independent components through event-driven queues and pipelines.

Embrace failure
Monitor everything, provide service even when parts start failing. Minimize and control dependencies, use abstract interfaces and virtualization, components have an SLA, consumers responsible for recovering from SLA violations. Automate everything. Components should automatically adjust and the system should learn and improve itself.

Embrace inconsistency
Pick for each feature where you need to be on the CAP continuum, no distributed transactions, inconsistency can be minimized by careful operation ordering, become eventually consistent through async recovery and reconciliation.

Save all your data
Data drives finding optimization opportunities, predictions, recommendations, so save it all. Know which data is authoritative, which data isn't, and treat it accordingly.

Infrastructure: use the right tool for the right job
Need to maximize utilization of every resource: data (memory), processing (CPU), clock time (latency), power. One size rarely fits all, particularly at scale. Compose from orthogonal, commodity components.


Facebook

Scaling takes multiple iterations
Solutions often work in the beginning, but you'll have to modify them as you go on - what works in year one may not work later. A good example is photos. Facebook currently serves 1.2 million photos a second. The first generation was built the easy way - don't worry about scaling that much - focus on getting the functionality right. The uploader stored the file in NFS and the meta-data was stored in MySQL. It only worked for the first 3 months but this didn't matter because time to market was the biggest competitive advantage they had. Having the feature was more important than making sure it was a fully thought out, scalable solution. The second generation was optimized - different access patterns were optimized for. Smaller images were accessed more frequently so those became cached. They also started using a CDN (Content Delivery Network). The third generation is an overlay system that creates a file that is a blob stored in the file system. Images are stored in a binary blob and you know the byte offset of the photo in the blob - so there's only one disk IO per photo.

Don't over design a solution - keep it simple
Just use what you need to use as you scale your system out. Figure out where you need to iterate on a solution, optimize something, or completely build a part of the stack yourself. Facebook spent a lot of time trying to optimize PHP, and ended up writing HipHop, a tool to convert PHP into C++. This generated a massive amount of memory and CPU savings. You don't have to do this on day one, but you may have to. Focus on the product first before you write an entire new language.

Choose the right tool for the job, but accept that your choice comes with overhead
If you really need to use Python then go ahead and do so, but realize with that choice there is overhead, usually across deployment, monitoring and operations. If you choose to use a service oriented architecture (SOA) you'll have to build most of the backend yourself and that often takes quite a bit of time. With the LAMP stack you get a lot for free. Once you move away for the LAMP stack, how you do things like service configuration and monitoring is up to you. As you go deeper into the services approach you have to reinvent the wheel.

Get the culture right
Build an environment internally which promotes building the right thing first and then fixing as needed, not worrying about innovating, not worrying about breaking things, thinking big, thinking what is the next thing you need to build after the building the first thing. You can get the code right, you can get the products right, but you need to get the culture right first. If you don't get the culture right then your company won't scale.


Instagram

Make use of existing cloud infrastructure

Don't reinvent the wheel when you can use solid and proven technology. Instagram runs 100+ instances of Ubuntu 11.04 on Amazon's EC2 cloud computing infrastructure. They also use Amazon's ELB (Elastic Load Balancer), which comprises three NGINX instances, with automatic failure recovery. The photos themselves go straight to Amazon S3 storage and they use Amazon CloudFront as their CDN (Content Delivery Network), which helps with image load times from users around the world (like in Japan, their second most-popular country).

Asynchronous task queuing
When a user decides to share out an Instagram photo to Twitter or Facebook, or when they need to notify a Real-time subscriber of a new photo posted, they push the task into the open source Gearman task management framework. Doing it asynchronously through a task queue means that media uploads can finish quickly, while the ‘heavy lifting’ can run in the background. There's about 200 workers, written in Python, consuming the task queue at any given time, split between the services they share to.

Push notifications
They use an open source Apple Push Notification Service (APNS) provider called pyapns, which is based on Twisted. It has handled over a billion push notifications for Instagram, and they report that its been rock-solid.

Real-time system-wide monitoring
With 100+ EC2 instances, it’s important to keep on top of what’s going on across the board. They use Munin to graph metrics system-wide, which sends an alert if anything is outside of its normal operating range. They write custom Munin plugins, building on top of Python-Munin, to graph metrics that aren’t system-level (for example, signups per minute, photos posted per second, etc). They use Pingdom for external monitoring of the service, and PagerDuty for handling notifications and incidents. For Python error reporting, they use Sentry, an open-source Django app. At any given time, they can sign-on and see what errors are happening across their system, in real time.

Selective use of NoSQL technology (like Redis)
Redis powers the main feed, the activity feed, the sessions system (here’s their Django session backend), and other related systems. All of Redis’ data needs to fit in memory, so they run several Quadruple Extra-Large Memory instances on EC2 for Redis, and occasionally shard across a few Redis instances for any given subsystem.


Sidenote on CAP
Eric Brewer's CAP Theorem or "the three properties of systems"
  • There are three properties of a system: consistency, availability and tolerance to network partitions (partitionability).  
  • You can have at most two of these three properties for any shared-data system. 
    • Consistency: write a value and then when you read the value you get the same value back. In a partitioned system there are time windows where that's not true. 
    • Availability: you may not always be able to write or read. The system may prevent you from writing because it wants to keep the system consistent.
    • Partitionability: divide nodes into small groups that can see other groups, but they can't see everyone.


Follow @dodgy_coder

Subscribe to posts via RSS

Wednesday, January 4, 2012

Modern Cross Platform Development

Why isn't there a modern technology available for using the same codebase to produce native apps on all of the currently popular platforms - I'm talking iOS (iPhone/iPad/iPod Touch), Android, Windows, Mac and Linux?

That was my original question before I started looking, and since then I've discovered there actually are plenty of new options out there for cross platform development catering for all of the above platforms.


A Brief History of Desktop UI Toolkits

In the 1980's the problem of a cross platform desktop user interface was for the most part solved by the X Window system, known as X11, (1984-) along with one of the first widget toolkits, Motif (1989-), which was built on top of X11. Back then, the dominant platforms used by business were Microsoft Windows and the various flavours of Unix, like Sun Solaris, HP-UX, IBM's AIX etc (later Linux came along and maintained full support for X11 and Motif). Developers who wanted to target multiple platforms such as these had this option of developing one codebase, usually written in C/C++, using X11 and/or Motif.  The UI code for the most part could remain the same and the application just needed to be recompiled with the provided X11 libraries.

Since then Motif has pretty much faded into the background and been replaced with newer widget toolkits, still built on top of X11, including Qt (1991-), wxWidgets (1992-) and GTK+ (1998-). These now run on many different platforms and bindings are available for many, many languages, including for their native C or C++.

These three free open source toolkits have been successful for the desktop application case but looking towards mobile and tablet platforms, these toolkits don't currently have the support there to take them into the future.

Qt
Native language: C++
Platforms: iOS (unofficial), Windows, Mac, Linux.

Probably the C++ based Qt widget toolkit is the most well established way of writing desktop cross platform applications. Smartphone support isn't really there yet, but there is an unofficial port to iOS. Linux's KDE desktop environment is written with the Qt toolkit. Many significant apps have been developed with Qt, including Autodesk Maya, VLC media player, Mathematica, Virtual Box and Skype. Qt is now owned by Nokia (although is still open source), and there was a release of a new version recently (Qt 4.8).

GTK+
Native language: C
Platforms: HTML5 (unofficial), Windows, Mac, Linux.

The C-based GTK+ widget toolkit is also a very well established way of writing cross platform desktop apps. Smartphone support isn't there, but there is an unofficial port to HTML5. GTK+ powers Chromium on Linux, the open source forerunner to Google's Chrome browser. The GNOME desktop environment is written with the GTK+ toolkit. The other notable app written with GTK+ is the one that launched the toolkit itself, GIMP, an open source bitmap image editor.

wxWidgets
Native language: C++
Platforms: iOS, Windows, Mac, Linux.

A C++ native mode toolkit that provides a thin abstraction to a platform's native widgets. It was originally developed as a desktop GUI toolkit in the same vein as GTK+ and Qt and support for iOS is still beta. There are a number of notable apps developed with wxWidgets including BitTorrent, Audacity, TortoiseCVS and RapidSVN.


Java and Silverlight

Sun's Java Swing UI Library (1997-) and Microsoft's Silverlight (2007-) were both attempts at "write once, run anywhere" (WORA) technology that provided a rich user interface library. Although technically successful, they failed in their attempt to become the ubiquitous technology that everyone uses to develop UIs. They both attempted to replace the 'native' look of apps developed on a particular platform and instead impose their own look and feel based on graphical primitives, which although being more powerful for developers, users on the whole didn't like.

As Johannes Fahrenkrug discusses here, people actually want to run Windows apps that look like Windows apps, and run MacOS apps that look like MacOS apps. To be fair, the Java Swing UI has actually undergone a lot of advances since it was first released and can now generate apps that do look perfectly native on all desktop platforms. The problem may be however that people's original experience of early Swing apps having a slow and inconsistent UI might have put them off using other Java apps and so contributed to its demise.

In the case of Microsoft's Silverlight and WPF, although not officially dead yet, they are now taking a back seat to newer technologies that were released by Microsoft at the September 2011 Build conference; Windows 8 allow developers to create new style 'Metro' applications by using either web technology (HTML5/JavaScript/CSS) or a traditional language - C#, VB.NET or C/C++ paired up with XAML for describing the UI. There's more detail about this topic on StackOverflow here for those interested.


The Rise of Web Applications and the App Store

The two big changes since the desktop UI toolkit days has been the rise of browser-based web applications and more recently the rise of downloadable apps running on smartphones and tablets such as Apple's iOS (powering the iPod touch, iPhone and iPad devices) along with Google's Android (powering a vast array of different smartphones and tablets from many hardware vendors). Google's recent Chrome OS also deserves a mention for creating an OS around the browser itself. These new class of devices offer a quick method of downloading, paying for and installing apps (often with just one click) and appear in the easy to use 'App Store' on iOS and 'Android Marketplace' on Android.

Microsoft is getting in on the App Store action a little late with its 'Windows Store' for Windows 8, which will be appearing some time in 2012. Its thought by Hal Berenson (a former Distinguished Engineer at Microsoft) that the upcoming Windows Phone 8 OS will be based on the same technology as Windows 8 and hence will unify  the development platform for Microsoft's desktop, tablet and smartphone operating systems. This will likely be announced some time in 2012, probably at the same time Microsoft launches the 'Windows Store'. This will mean Windows 8's new 'Metro' style apps on the Windows Store will run on phones, desktops and tablets - something that neither Apple nor Google can lay claim to, just yet. Add in the possibility of an XBox update which adds support for running Metro apps, and you have a huge carrot which will make the unified Windows 8 platform very attractive to both application and game developers.


Choosing Your Platform - Desktop, Web or Mobile Application?

When choosing your platform, if you need full access the underlying file system, or access to hardware devices like serial ports, microphones, webcams, etc, then you may be better off staying with a desktop application. If you need platform independence on top of this then you can go with one of the traditional widget library technologies like wxWidgets, GTK+ or Qt to provide a full cross platform UI solution.

Alternatively, if you don't need so much access to hardware and can remain restricted to the browser, then HTML5 and JavaScript may be the way to go. Browser based web applications have their own set of problems however, including the browser incompatibilities, varying support for the HTML/CSS web standards and the Document Object Model (DOM). In addition, web application development generally makes it harder to create rich UI apps than for desktop or mobile applications. HTML5 will provide massive improvements, but web apps are still running in a browser and so will always remain sandboxed and limited in what they can achieve (no access to file system, serial ports, microphone, webcam, etc.).

The main advantage of the browser app however, and its a massive one, is that its everwhere and supported by every device, so if HTML5 takes off, then it could become the defacto standard for developing apps of any kind, desktop or not. As Jeff Atwood discusses in his seminal blog post All Programming is Web Programming; "the web is the most efficient, most pervasive, most immediate distribution network for software ever created - its almost completely frictionless".  As Atwood mentions, more and more users gravitate towards preferring to run their apps inside the browser, on smartphones and on tablets where things 'just work' and there's generally nowhere near as much friction caused by the traditional desktop software setup and update process.

A third option available now is the cross platform mobile development SDK as detailed below (Mono, Appcelerator Titanium, Rhodes, PhoneGap, MoSync, Moai, Corona SDK and JUCE). Smartphone and tablet based applications are taking off, and these SDKs allow you to write once and run on any of these new class of devices, as well as in some cases also being able to run on the traditional desktop. These would seem to offer some of the 'power' of the desktop in terms of native code execution speed and access to hardware functionality, along with the enourmous 'frictionless' benefit that you get when publishing to an app store, where installing an app is literally a one click operation.

Mono
Native language: C#
Platforms: iOS, Android, Windows, Mac, Linux, Browser (e.g. via ASP.NET WebForms or MVC).
Cost: Windows, Mac & Linux: free. Android and iOS: from US$399 each. Free trial available.
License: LGPL/GPL/X11 combination. Commercial license available.
Source: Mono for Windows/Mac/Linux is open source. Mono for iOS/Android is closed source.

The C# based Mono cross platform library allows apps to be built using purely C#. However this is not strictly a cross platform UI library, since each supported platform has its own different set of Mono C# UI libaries, each with their own capabilities. The idea is that you build your software using the MVC (Model View Controller) pattern, so that the Model and Controller components (both written in C#) can be shared across all platforms without any changes. Only the View component needs to be re-written for each platform (again, in C#). Mono targets both mobile and desktop apps, however if you are just looking at developing a desktop application, then Mono probably isn't a big improvement over GTK+ or Qt, after all a well written C++ Library (with a Model and Controller component for example) will enjoy the same capability to be shared across more than one platform if you use Qt or GTK+ and then you wouldn't need a different UI library on each platform to create your view. There are several advantages that Mono has over Qt or GTK+ however - firstly in leveraging a team's existing knowledge (and codebase) of C# which is a popular language. Secondly, being able to target iOS, Android and the browser. Lastly, via Mono's .NET CLR implementation (Common Language Runtime), code is compiled into modules of bytecode, which are binary compatible across all the supported platforms.

There is also an open source library for Mono called MonoGame which lets you port with minimal effort XNA based games (which originally target the .NET platform and run only on Windows Mobile, Windows and XBox) to any of the Mono platforms such as MacOS, Linux, iOS and Android.


Appcelerator Titanium
Native language: JavaScript, Python and Ruby
Platforms: iOS, Android, Windows, Mac, Linux.
Cost: Community Edition is free. Indie Edition (extra APIs, help, support): US$499 per year.
License: Apache Public License v2
Source: Open source


An open-source solution which allows you to use web development languages (HTML, JavaScript, CSS, Python and Ruby) to build mobile and desktop apps. App data can be stored in the cloud or on the device, and apps can take full advantage of hardware, particularly camera and video camera capability. Appcelerator apps go through a complex compilation and optimization process which result in it creating apps that look, feel, and perform just like native apps, because you are using native UI components... so an iPhone app developed with Titanium will actually feel like an iPhone app. They also offer an API repository marketplace to buy and sell code to extend Titanium. One of the downloadable components allows you to develop your app using an MVC (Model View Controller) pattern. There is an active developer community Q&A site for Titanium developers which is similar in usage to StackOverflow.

Rhodes
Native language: Ruby
Platforms: iOS, Android, Windows Mobile, Blackberry.
Cost: Free
License: MIT License
Source: Open source

Rhodes is an open source, Ruby-based framework that allows the development of native apps for a wide range of smartphone devices and operating systems. The framework lets you write your code once and use it to quickly build apps for every major smartphone. Apps can take full advantage of available hardware, including GPS and camera, as well as location data. Rhodes enforces a strict MVC (Model View Controller) pattern on your apps. Views are written in HTML5 while Controllers and Models are written in Ruby.

PhoneGap
Native language: HTML5/JavaScript
Platforms: iOS, Android, Windows Mobile, Blackberry, Symbian, Palm.
Cost: Free
License: Apache License, Version 2.0
Source: Open source

PhoneGap is an open source framework that helps you develop apps for smartphones using web development languages such as JavaScript and HTML5. It also allows for access to hardware features including GPS/location data, accelerometer, camera, sound and more. PhoneGap lets you take a web app, run it in a UIWebView, and through javascript you can access iPhone features such as the camera an accelerometer. This means that it won't necessarily have the look and feel of a native app (like the other cross platform SDKs listed here). The idea is that you develop your web app like you normally do, and then use PhoneGap to 'bridge the gap' to the phone, and give you access to phone's hardware, that traditionally you couldn't access from a web-only app.

MoSync
Native language: C++
Platforms: iOS, Android, Windows Mobile, Blackberry, Symbian.
Cost: Free for Indie developers. From €199 (Euros) per year for Enterprise developers.
License: GPL v2. Commercial license available.
Source: Open source

The MoSync Mobile SDK is a cross-platform mobile application development SDK which allows the development of native apps. Free open-source, it is based on C++ but allows development also in HTML5 and JavaScript. MoSync provides access to a wide range of underlying device functionality, via a C++ SDK or optionally via JavaScript.  It requires probably a greater degree of software skill from the developer, but in principle can enable a rich variety of different kinds of application.

Moai
Native language: Lua
Platforms: iOS, Android, Chrome Web Store, Windows, Mac, Linux.
Cost: Free
License: Common Public Attribution License Version 1.0 (CPAL)
Source: Open source

Although intended to be a mobile game development SDK, I think it deserves a mention here due to its unique scripted approach to cross platform development. Games developed with Moai run on iOS and Android as well as the Chrome Web Store, Windows, Mac and Linux. Designed to be programmed with the Lua scripting language, Moai is designed for experienced game developers who wish to use Lua for mobile development. The Moai framework itself is written in C++ and is intended to be called from the Lua scripting language, but can also be called from any other language supported by the host platform. The Lua script is run as interpreted byte code, but since very few Lua instructions are processed among all the input handling, this means that rendering, animation, collision detection, and physics math runs natively. Moai's physics engine for example is the Box2D open source C++ library. Moai is free and open source, however to build apps for iOS devices you'll need the iOS SDK and the Xcode IDE (presumably running on MacOS) and be a member of the Apple iOS developer program (US$99/year). To build apps for Android you'll need the Android SDK, the Eclipse IDE and an Android device.

Corona SDK
Native language: Lua
Platforms: iOS, Android, Kindle Fire, Nook Color.
Cost: US$199/year for Android. US$199/year for iOS. $349/year for all platforms. Free trial available.
License: Commercial, price as above.
Source: Closed source

A similar toolkit to Moai in that its primarily aimed at game developers, and apps are written with the Lua scripting language. Corona SDK was developed by two former Adobe mobile engineers and has been in development since 2007. It features a proprietary OpenGL-ES rendering engine, which allows for full hardware acceleration of graphics, including sprites that animate at full GPU speed. The Corona physics engine is built around Box2D as with Moai. Its free to try Corona and run your apps in a simulator on your desktop computer, but to build an app and publish it to an App Store, you'll need to pay a yearly subscription fee (of either US$199 per year for Android or iOS or the premium subscription of US$349 for all platforms). Your apps are built "in the cloud" on Corona's server. Note that if you are developing for iOS you'll still need to pay the yearly Apple iOS developer program fee which is currently US$99. There seems to be extensive documentation available for Corona and an active developer community forum. There has been a recent push to promote Corona for use not only for developing games but also for general apps and also interactive ebooks.

JUCE
Native language: C++
Platforms: Windows, MacOS, Linux, iOS, Android (Note that Android support is a work in progress).
Cost: Free for GPL license. Commercial license from £399 (UK pounds) per product.
License: GPL. Commercial license available.
Source: Open source

JUCE is an all-encompassing C++ class library for developing cross-platform software. Its designed to contain everything you're likely to need to create most applications, and is particularly well-suited for building highly-customised GUIs, and for handling graphics and sound. JUCE is developed by Raw Material Software and consists of a small team of developers based in London, England, founded by Julian Storer in 1999, who is still the primary developer today. It would probably be best suited to experienced C++ developers. Julian Storer himself is a professional C++ coder with over 15 years of C++ experience; he takes pride in the fact the source for JUCE is literate, coherent, cross-platform and high quality. Adding JUCE to your C++ application is very simple - the easiest way involves simply including juce.h in your files and adding a single .cpp file to your project. No need to compile any libraries or worry about dependencies.

Follow @dodgy_coder

Subscribe to posts via RSS