Microservices architecture

+ No comment yet
In this edition, Rahul (rahul dot amodkar at indexnine dot com) reviews Microservices architecture while looking at the things to consider when it comes to choosing it. He lists  out the drawbacks and the advantages of using Microservices architecture.

Microservices has been a buzzword in software engineering recently. Everyone wants to build their application around Microservices architecture. Before you jump onto the bandwagon, lets do a critical review of Microservices. We will look at the cases where it is appropriate along with  advantages and disadvantages. 

Before we proceed let us look at how to define a microservice. Wikipedia says:
In computing, microservices is a software architecture style, in which complex applications are composed of small, independent processes communicating with each other using language-agnostic APIs.  These services are small, highly decoupled and focus on doing a small task.
 A Microservice

  • Addresses a small problem domain.
  • Is built and deployed independently.
  • Runs in its own processes.
  • Segregates data and config for its own use.
  • Integrates via well known interfaces.

A collection of such microservices forms a usable application. 

When to use Microservices 

Microservices Architecture is an excellent choice when :
  • The system is too complex or too big and it becomes difficult to manage. 
  • The system is expected to handle high traffic & load and needs to be highly scalable. 

Drawbacks of microservices

Microservice architecture is very attractive, but even staunch supporters agree with its drawbacks.  
  • Adds complexity to development due to its distributed nature.
  • Adds overhead in terms of costs and operational complexity (build-test-deploy-run).
  • Time to market may be hit adversely due to the distributed nature of the application.
  • Monitoring the application in production deployment becomes a complex job, with multiple services.
  • Service interface versioning needs to be managed for the multiple services.
  • The operational challenges of Microservices architecture mean you need high quality DevOps and release automation skills as part of your development team.
  • The asynchronous communication and distributed nature of the microservices based system poses challenges for testing the system as a whole.
  • Operational expenditure could be significantly higher depending on the complexity of the system.

Benefits of microservices

The architecture also brings benefits that has made it so popular:
  • Systems are inherently scalable as the services built this way are loosely coupled. The scalability is improved further if the communication between the services is asynchronous using a Enterprise Service Bus (ESB). 
  • It improves the team autonomy as smaller team have complete control over the microservice. These smaller team can deliver at a higher speed of delivery as they are focused on the specific service. 
  • It highly increases the overall availability of the system when combined with Fault Tolerant Architecture.
  • It allows each service to be built using the most appropriate tool and language for the job. 
  • Multiple teams can deliver relatively independently of each other under this model.
  • The approach eliminates long-term commitment to a single technology stack.
  • The development efforts are more scalable as one can develop, deploy and scale each service independently.
  • The product is more agile as defined interfaces can be use to completely swap out components if required.


The recommended approach that has worked with many teams is to start with a monolithic design with a clear mandate to break it down later into services and as boundaries between services become clear. This phased approach from monolithic to microservices has a higher success rate as compared to starting out with microservices from scratch. Start with a microservices approach right from the start only if you have extreme clarity about the service boundaries. 

On the flip side, be aware and educate your team of your long term strategy so you do not get stuck with monolithic glop beyond v1.0.


While there are many advantages of applying Microservices architecture either for a greenfield or a brownfield project, be prepared to pay “microservices tax” due to the various drawbacks mentioned earlier. 

Paying the tax could however lead to a cleaner, agile and scalable system.



Apache Kafka: What sets it Apart?

+ No comment yet
In this edition, Rahul (rahul dot amodkar at indexnine dot com) looks at the advantages of Apache Kafka, the distributed commit log messaging system, that make it a leading messaging solution when it comes to large scale streaming data processing applications. 

final-ADVANTAGE - Copy - Copy.png

Each day, large amounts of data and metrics are collected from real time activity streams, performance metrics, application logs, web activity tracking and much more. Modern scalable applications need a messaging bus that can collect this massive continuous stream of data without sacrificing good performance and scalability. Apache Kafka is built ground up to solve the problem of a distributed, scalable, reliable message bus.


Apache Kafka is a distributed messaging system originally built at LinkedIn and now part of the Apache Software Foundation. In the words of the authors : “Apache Kafka is publish-subscribe messaging rethought as a distributed commit log”.

While there are many mainstream messaging systems like RabbitMQ and ActiveMQ available, there are certain things that make Apache Kafka stand out when it comes to large scale message processing applications.


A single Kafka broker (server) can handle tens of millions of reads and writes per second from thousands of clients all day long on modest hardware. It is the preferred choice when it comes to ordered durable message delivery. Kafka beat RabbitMQ in terms of performance on large set of benchmarks. According to a research paper published at Microsoft Research, Apache Kafka published 500,000 messages per second and consumed 22,000 messages per second on a 2-node cluster with 6-disk RAID 10.

Source:  research.microsoft.com


In Kafka, messages belonging to a topic are distributed among partitions. A topic has multiple partitions based on predefined parameters, for e.g all messages related to a user would go to a particular partition. The ability of a Kafka topic to be divided into partitions allows the topic to scale beyond a size that will fit on a single server. The concept of dividing a topic into multiple partition allows Kafka to provide both ordering guarantees and load balancing over a pool of consumer processes.

Another aspect that helps Kafka to scale better is the concept of consumer groups (a collection of message subscribers/consumers). The partitions in the topic are assigned to the consumers in the consumer group so that each partition is consumed by exactly one consumer in the group. This mechanism aids in parallelism of consuming the messages within a topic. The number of partitions dictates the maximum parallelism of the message consumers.

Distributed By Default

Kafka is designed very differently than other messaging systems in the sense that it is fully distributed from the ground up. Kafka is run as a cluster comprised of one or more servers each of which is called a broker. A Kafka topic is divided into partitions using the built-in partitioning. It has a modern cluster-centric design that offers strong durability and fault tolerance guarantees. The Kafka cluster comprised of multiple servers/brokers can be spread over multiple data centers or availability zones or even regions. This way the application would be up and running even in a disaster scenario of losing a datacenter.


Kafka partitions are replicated across a configurable number of servers thus allowing automatic failover to these replicas when a server in the cluster fails. Apache Kafka treats replication as the default behaviour. This ability of the partitions to be replicated makes the Kafka messages resilient. If any server with certain partitions goes down, it can easily be replaced by other servers within the cluster with the help of the partition replicas.


Messages are persisted on disk for a specific amount of time or for a specific total size of messages in a partition. The parameters are configurable on a per topic basis. One can choose to persist the messages forever. The time to be persisted is configurable per topic.

Guaranteed Ordered Messages

Kafka guarantees a stronger ordering of message delivery than a traditional messaging system. Traditional messaging systems hand out messages in order, but these messages are delivered asynchronously to the consumers. This could result in the message getting delivered out of order to different consumers. Kafka guarantees ordered delivery of messages within a partition. If a system requires total order over messages then this can be achieved by having a topic with no partitions. But this comes at the cost of sacrificing parallelism of message consumers.

Industry Adoption

Apache Kafka has become a popular messaging system in a short period of time with a number of organisations like LinkedIn, Tumblr, PayPal, Cisco, Box, Airbnb, Netflix, Square, Spotify, Pinterest, Uber, Goldman Sachs, Yahoo and Twitter among others using it in production systems.


Apache Kafka is an extremely fast and scalable message bus that supports publish-subscribe semantics. Due to its distributed and scalable nature, it is on its way to becoming a heavyweight in the scalable cloud applications arena. Although originally envisioned for log processing, IoT (Internet of things) applications will find Kafka a very important part of architecture due to the performance and distribution guarantees that it provides.

Want to learn more about how to build scalable applications? Please take a look at our Building Scalable Applications blog series Part I, Part II and Part III.

Building Scalable Applications: Handling Transient Failures in Cloud Applications

+ No comment yet
In this edition, Rahul (rahul dot amodkar at indexnine dot com) looks at an approach to handle the transient failures encountered in cloud platform deployments. We will look at a mechanism that can be employed to take care of transient failures without losing data or impacting user experience.


While there are numerous advantages of deploying on the cloud, there are no guarantees that the cloud platform services will respond successfully every time. In a cloud environment periodic transient failures should be expected. The approach should be to minimize the impact of such failures on the application execution by anticipating and proactively handling failures.

The Problem With Cloud Services

The cloud is made up of hardware components that work together to present a service to the user. Since hardware is subject to failure, cloud services cannot guarantee 100% uptime. Small failures could cascade and affect multiple services, all of some of which could be down for brief periods of time.

When the consumer’s use of the cloud service exceeds a maximum allowed throughput, the system could throttle the consumer’s access to the particular service. Services deploy throttling as a self-defense response to limit the usage, sometimes delaying responses, other times rejecting all or some of an application’s requests. The onus is on the application to retry any requests rejected by the service.

What Needs To Be Done

Cloud applications need to retry operations when failures occur. It does not make sense to retry the operation immediately because most failures should be expected to last for a few minutes at least. We will consider a scenario where the database service is unavailable for a short time.

The figure above shows the flow of the operation which encounters a transient failure and the possible approach to recover from it. The message sent by the web instance is added to the primary message queue. This message is picked up for processing by the worker instances.

When the worker tries to write data to the database tier, it encounters a failure. In this case, the worker adds the data to be written to a “Deferred Processing Queue”.

A scheduled job runs every 5 minutes, listens to the “Deferred Processing Queue” and consumes the messages from this queue for processing. The scheduled job reinserts the message into the primary message queue where it is read by the worker instances and processed successfully if the database service is available. If not, the same process is followed again. This allows the cloud application to process the messages at a deferred time, and makes it resilient to failures.


Transient failures are a common phenomenon in cloud applications. A cloud-based application is expected to withstand such transient failures and prevent loss of data even under extreme circumstances.

Building Scalable Applications Part 3 : Cloud features that help you scale

+ 1 comment
In this edition, Rahul (rahul dot amodkar at indexnine dot com) looks at a typical cloud architecture that can support many types of applications. We will examine each tier and explore concepts such as load balancing and auto-scaling.

In previous posts, we covered the benefits of moving to the cloud for scale and the design principles of building scalable applications. In this post, we will look at a typical reference architecture for a cloud based scalable application and cloud features that help your application scale.


The below listed figure illustrates a reference architecture commonly used by scalable applications. The architecture has the following usual suspects that allow it to handle high traffic and load patterns experienced by typical scalable applications:

  • Load Balancer(s) for the web tier.
  • Auto-scaling for web and worker instances.
  • Message queue
  • Cache
  • SQL and/or NoSQL database(s).

indexnine FINAL.png

Load Balancer

Load balancers are used to distribute load on application services across multiple systems. This allows the application to scale horizontally, and allows the application to add more capacity transparently in response to demand. By fronting application services using a simple proxy, a load-balancer provides clients a single internet location to communicate with, while fanning out  backend processing across multiple service instances. A load balancer can be used for any service within the application as needed. Most commonly a load balancer is used to front web instances.

Load balancers typically use a round-robin algorithm to route traffic to the service layer. In advanced configurations, they can also be configured to control the volume of traffic routed to different instances.

Sticky Sessions

For legacy applications, load balancers also support session stickiness, which means the load balancer routes all requests for a given session to a single instance. This can be used in case the concerned tier is not stateless. Since implementations of load balancers vary, consult the respective documentation to understand how sticky sessions are handled.

Most cloud vendors have load-balancing available as-a-service. On Amazon Web Services, you can configure a load-balancer to front a set of EC2 instances that checks for health of the instances periodically and routes traffic to them only if they are healthy.

Web Tier

A stateless web tier makes it easy to support horizontal scaling. As discussed in part 2, REST web services are designed to be stateless and therefore conducive to scale horizontally. Some modern frameworks that allow rapid creation of web apps are Dropwizard, Spring Boot (java), node.js and express (javascript).


Since the web tier is consumer facing, it is normally set up to auto-scale. Most cloud vendors support autoscaling by monitoring certain characteristics of the instances to be scaled. On Amazon Web Services, it is possible to track CPU usage or network bandwidth usage of instances and respond to extreme events by scaling out (expanding) or scaling in (contracting). To avoid cost escalation, you can also specify a higher limit for the number of instances auto-scaling will spawn.


Caching drives down access times for most frequently used documents. Since documents are stored in-memory the response times for web apps can improve manifold by using a cache. For e.g. User information might hardly change during the course of a session, but related information such as user permissions and role information needs to be accessed frequently. Therefore, the user information and the related roles and permissions are prime targets to be cached. This will result is faster rendering of pages that need to assess permissions before displaying data.

Redis and Memcached are two of the most popular caches available. Amazon web services provides both the implementations in the Elasticache offering.


Content-Delivery-Networks or CDNs are used to deliver static artifacts such as pictures, icons and static HTML pages much faster than a regular “single-source” website. Cloud vendors provide access to CDNs that will replicate static resources closer to the customer, thereby reducing latency. This results in excellent load times especially if there are large images and/or videos being used on the site or application.

Amazon Web Services CloudFront automatically identifies and serves static content from the closest datacenter irrespective of the region the site is hosted in. This results in drastic reduction of latency and faster loading of web artifacts.

Message Queue

Asynchronous communication ensures that the services/tiers are independent of each other. This characteristic allows the system to scale much farther than if all components are closely coupled together. Not all calls in your system need to be asynchronous. You can use the following criteria to qualify a call as asynchronous communication.

  • A call to a third party or external API. 
  • Long running processes
  • Error prone/changed frequently methods.
  • Any operation that does not need an immediate action as a response. 

While you implement the message bus based asynchronous communication, you need to take care that the message bus can scale to the rise in traffic. RabbitMQ is a popular message-oriented middleware used by many applications. You can also consider ActiveMQ, Kafka and Amazon SQS as the other message queue options.

Worker Tier

Similar to the Web tier the worker tier too needs to support horizontal scaling. The worker instances are independent processes that listen to the message queue and process the message as they are received.

The message bus size is a good parameter to monitor for scaling such that the number of worker instances increases with the increase in the number of message in the queue. Amazon AWS Auto Scaling groups and Rackspace Auto Scale are some examples of auto scaling options available with the respective cloud platforms.

Database Tier

A typical Database Tier of a scalable application would make use of both NoSQL and SQL databases as each of these have their own advantages. NoSQL can be used in the following scenarios where:

  • A relational database will not scale to your application’s traffic at an acceptable cost.
  • The data is unstructured/"schemaless". The data does not need explicit definition of schema up front and can just include new fields without any formality.
  • Your application data is expected to become so massive that it needs to be massively distributed
  • The application needs fast key-value access.

You should avoid the use of NoSQL and use RDBMS databases in scenarios where:

  • Complex/dynamic queries are needed. Complex queries are best served from an RDBMS.
  • Transactions need guarantee of ACID (Atomicity, Consistency, Isolation, Durability) properties.

When it comes to NoSQL databases there are multiple options available like MongoDB, Cassandra, AWS DynamoDB and CouchDB. Google recently announced the availability of, Google Cloud Bigtable, a NoSQL database that drives nearly all of Google’s largest applications including Google Search, Gmail and Analytics.


We discussed the various components of a reference architecture that can be used to run different types of applications on the cloud. Each application will dictate the nature and scale of usage of these different components, but most applications will need all of these components to achieve scale. Most cloud vendors have managed service offerings that provide access to these components. 

Building Scalable Applications (Part 2): Design for the cloud

+ No comment yet

This is part 2 of our series of blog posts targeting building scalable applications on the cloud. In this post, Rahul (rahul dot amodkar at indexnine dot com) looks at 5 key design principles to follow while building a cloud-based application.

In the previous post, we covered the benefits of moving to the cloud for scale. In this post, we will look at some best practices to build applications for the cloud.

1. Use messaging to decouple components

One of the important principles of scalable application design is to implement asynchronous communication between components. To start with you can break down the application into multiple smaller services and deploy a message queue for communication between these services.  A simple example of this would be to have your application’s Web instances put messages into a queue which are then picked by worker instances.

Such a mechanism is very effective for processing user requests that are time consuming, resource intensive, or depend on remote services that may not always be available.
Decoupling using a message queue

Keeping the communication asynchronous allows the system to scale much farther than if all components were closely coupled together.  By increasing compute resources for the workers, larger workloads can be disposed of quickly and in parallel. From a user experience standpoint, there are no interruptions or delays in the activity flow improving the user's perception of the product.
Most importantly, this allows the web tier of the application to be lightweight and therefore support more users per instance of compute that runs in the cloud.

2. Be Stateless

In order to scale horizontally, it is important to design the application back-end such that it is stateless. Statelessness means that the server that services a request does not retain any memory or information of prior requests. This enables multiple servers to serve the same client. By being stateless (or offloading state information to the client), services can be duplicated and scaled horizontally, improving availability and catering to spikes in traffic by scaling automatically.

REST or Representational State Transfer is a good way to architect back-end services. REST lends itself nicely to a stateless protocol and adhering to the principles of REST provides rich integration possibilities as it is based on the well-known HTTP protocol. Good quality clients to use the protocol are available in all languages, making access to the API simple and open regardless of client language preference.

3. Cache aggressively

Caching improves performance by storing recently used data for immediate reuse. Application throughput and latency are typically bound by how quickly data and context can be retrieved, shared and updated. Add cache at every level from the browser, your network, application servers and databases. You can implement caching by leveraging Content Delivery Networks (CDN) especially for static data or by using caching solutions like Redis and Memcached. Cache aggressively in order to significantly increase the application’s performance and its ability to scale.

A fast, in-memory cache speeds up look-ups

Before adding elements to a cache, assess the following 2 things:

  • How often is this data accessed ?
  • How often does this data change ?

If data is accessed very often and changes rarely, then this type of data is a prime target to be cached.

4. Expect Transient failures

A large cloud application spans many compute containers (VMs), Messaging services (Queues), Databases and other services. Although many managed services on the cloud provide excellent availability, it is still possible that failures may happen.

Transient failures may manifest themselves as temporary service outages (e.g unable to write to db) or a slowdown in performance (throttling).

Failing operations due to transient failures is not a good option.  Instead, implement a strategy that retries the operation.  Do not retry immediately because outages in most cases may last for a few minutes or more.  Implement a strategy that delays the retry thus allowing the resource to recover. Implementing such smart retry policies will help handle busy signals or outright failures without compromising user experience.

5. Don't be chatty

Since a cloud application is spread across multiple component services, every interaction might involve connection overhead. This means going back and forth many times can be detrimental to performance and expensive in the long run.

Pay attention to how data is accessed and consumed. Wherever possible, process data in batches to minimize excessive communication. For user interfaces, try and cache objects that may need frequent access, or better still, query most data needed for a view upfront and cache on the browser side to improve performance and reduce round-trips.

When it comes to user interfaces, a pure object-based REST API may not be sufficient to provide all the data needed for screens (especially dashboards), upfront. Avoid the temptation to make multiple calls to the back-end. Instead, build an aggregation API whose data can be cached to improve performance.

Remember, on the cloud, innocuous looking functions may end up making a web-service call, adding overhead to your functionality.


Use these design principles while building your cloud application. These principles will help you build applications that can scale to meet demand by leveraging auto-scaling. By recognizing the pitfalls of the cloud environment and designing around it, you can build fault-tolerant apps that users are happy with.

Building scalable applications (Part 1): Leverage the cloud

+ 1 comment
This is part 1 of our series of blog posts targeting building scalable applications on the cloud. In this post, Rahul (rahul dot amodkar at indexnine dot com) points out the advantages to using the cloud to build scalable applications. In future posts, we will cover reference architectures and examine different components of a cloud-application.

A friend of mine tells me a story repeatedly. Back in 2003/4, he co-wrote an online news aggregation web app when RSS feeds were first taking off. The app had every social news application feature that you could think of. Imagine Digg + StumbleUpon + Google News all in one (and in 2003 !). Things were going great guns until the time a popular blogger chose to write about the site. A couple of hours later, the site crashed in the middle of the night. Next morning, the negative reviews started. Large number of users reported the site was down or slow to respond. My friend was never able to capitalize on a viral uptake in user base.

Consumer facing applications can go viral very quickly. If an application is accessible via a smartphone interface, the power of social media can fuel exponential growth of your user-base as well as data.

Monolithic applications fail to scale up to the demands of a growing business. The failure of these applications in responsiveness and scalability results in customer dissatisfaction leading to loss of brand value and of course revenue.
Airbnb user base uptake. Source : blog.rjmetrics.com
The above graph shows Airbnb’s user base expand virally between May and August 2011. They added close to 500,000 users in the space of 3 months. A similar but more recent example is Twitter's Periscope app which racked up more than 1 million users just 10 days after launch. It would be extremely difficult to take care of such swift scale in traffic without a cloud deployment.

In this series of blog entries, we will take a look at some of the aspects that help us build a scalable cloud-deployed application. In this first part, we will look at the advantages of building scalable applications that leverage the cloud.

Unlimited Resources

The cloud provides the ability to scale on demand and with almost no practical limits. It is possible for infrastructure resources like CPU, memory and storage to be provisioned in a matter of minutes as opposed to hosting and operating those locally. In traditional on-premise data-centers, growth in demand has to be catered to by procuring new hardware. This is not only expensive, but may lead to over-provisioning of resources, not to mention the lead time required to setup and run.


As traffic spikes, cloud based applications can scale on-demand. You can even configure automatic scaling such that as the traffic spikes, resources are allocated and as the traffic declines the resources are relinquished. (We will look at Auto-scaling in details in future posts of this series). This helps the application use excess capacity only when needed.

Low Costs

Cloud adoption cuts down your Capex costs in a big way. It does not require a significant up-front capital expenditure and requires considerably few internal resources to maintain and administer. Operating costs in a cloud environment can be monitored and controlled as per your budgets.

Pay As You Go

Cloud platforms do not need any up-front commitment by users. Most cloud platforms allow you to pay for actual resources consumed. Resources like compute (CPU) are usually billed on a per-hour usage model whereas other resources like network or storage are billed on bandwidth and storage consumed. This approach takes away a large component of any upfront payments for businesses. It also levels the playing field, allowing smaller companies or even individuals to start cloud businesses that succeed.

Time to Market

Be it an established business house or an individual entrepreneur, one advantage of the cloud that excites everyone, is the ability to push products to the market faster. Traditionally it takes anywhere between 6-8 weeks for IT server provisioning. Compare this to the cloud that can provision the IT resources in a matter of hours if not minutes.

High Availability

Cloud platforms have presence in multiple regions. Each region is a distinct geographic area which in turn has multiple, isolated data centers. Applications hosted in cloud can be deployed on multiple data centers in order to make them highly available. Since the application is not dependent on one physical location, outages such as loss of network or electricity do not translate to application downtime.

Disaster Recovery

To protect against natural disasters and calamities, applications can also be hosted in multiple regions using data replication and DNS failover. This allows applications to survive outages of complete regions, by restoring business operations quickly with minimal downtime. Providing disaster recovery solutions using traditional means was reserved for the deepest pockets before the cloud arrived.


Cloud adoption has allowed organisations to scale faster to the needs of a growing business without the headache of managing infrastructure. It is no wonder that cloud has become an integral part of any scalable application. Coupled with “pay as you go” pricing and economies of scale, cloud vendors provide incredible value for computing needs that cannot be ignored.

Architecture for applications on the cloud is a different ball-game and involves various components in tiers that need to be put together to create a functioning application. In our next post, we will delve into the design aspects of a scalable cloud application. Stay tuned !

Mobility strategy: Why your strategy should be responsive

+ No comment yet

In today's world, it is imperative to have a strategy for consumers on smart phones and tablets. The statistics speak for themselves:

In 2012, a study found that 22% of web content was being consumed by smartphones and tablets. Two short years later, the figure stands at around 56%.

The internet is full of statistics about how content consumption is moving mobile with figures between 40 - 60% thrown up by a variety of articles. Nothing is more definitive than a peep into our own habits as consumers. For example, since the advent of zippy smartphones,  I access web content almost exclusively on my phone and tablet. I have only accessed web content (casual reading excepting stackoverflow) using a laptop or desktop maybe 2-3 times over the past year.

Given the statistics, what should be my strategy ?
To answer this, I'll make a distinction between "web sites" and "web apps".

  • 'Web apps' are services such as Quora/Facebook/LinkedIn which need to enable a rich level of interaction with the user.
  • 'Websites' contain content that will be used by end users to learn about a company or service. 

IMHO the strategy in both these cases needs to be different. 

Web apps need to have a 2 pronged mobile strategy

  1. A native app on Android, iOS (and dependent on your target customer, Windows).
  2. A responsive web interface, even if with limited features that cross sells the native apps.

#1 because web interfaces on tablets and smart phones (as of early 2015) are still not performing well enough to be on par with their native counterparts. Also, a connected experience such as sharing content or interacting with hardware is more difficult with a web app and needs some nifty frameworks such as Cordova to be implemented.

#2 because in 2015 there cannot be an excuse to provide a bad interface for a large number of users who may potentially install your app. Again, even if with limited features, a responsive strategy is very important to keep your user base sticky. Think about your responsive site as the advert that nudges users to install the app but also provides instant gratification by providing most used features without the app.

Websites should be responsive
In most cases classic web sites do not need a native app for improved interactivity. In this case, the only avenue for end users to understand what you stand for is the website. And that website better look good and load fast on my phone or I'll just click on the next search result. 

Remember m.mysite.com ? Whats wrong with that strategy ?
Nothing. However, m.mysite.com was a solution for a time and age that has served its usefulness. Last decade, it was possible to make the distinction between "desktop" and "mobile" interfaces. Fast forward to 2012, the number, type and form-factor of devices accessing this content has dramatically changed. There is no more "desktop" and "mobile", instead there are myriad devices of different form factors. The strategy of differentiating between a mobile and a desktop version does not work any more. 

Another problem is what i call "Design Consciousness". Most apps created in the last decade were unconscious in this regard. Web and mobile apps created in the last decade had almost no resemblance to each other and therefore squandered a brand-building opportunity. This is natural since these apps were viewed differently, and probably even had different design teams and strategies.

Responsive design came about as a natural outcome of all of the following:

  • Speed of cellular networks
  • Processing speed of devices carried by users
  • Touch interfaces
  • Mobile and Tablet form factors with a bizarre array of resolutions.
  • HTML5 and CSS3 improvements.
  • Modern browser compatibility and standards adherence.

A responsive strategy saves you money as it covers all potential customers that reach your website or app without the need for separate investments for each. It is imperative to have a responsive strategy to reach out to the widest audience possible.

Further Reading
Nice article about Responsive Design and benefits: