<p>In general, what kinds of design decisions help an application scale well?</p>

<p>(Note: Having just learned about <a href="http://en.wikipedia.org/wiki/Big_O_notation" rel="nofollow noreferrer">Big O Notation</a>, I'm looking to gather more principles of programming here. I've attempted to explain Big O Notation by answering my own question below, but I want the community to improve both this question and the answers.)</p>

<p><strong>Responses so far</strong><br>
1) Define scaling. Do you need to scale for lots of users, traffic, objects in a virtual environment?<br>
2) Look at your algorithms. Will the amount of work they do scale linearly with the actual amount of work - i.e. number of items to loop through, number of users, etc?<br>
3) Look at your hardware. Is your application designed such that you can run it on multiple machines if one can't keep up?  </p>

<p><strong>Secondary thoughts</strong><br>
1) Don't optimize too much too soon - test first. Maybe bottlenecks will happen in unforseen places.<br>
2) Maybe the need to scale will not outpace Moore's Law, and maybe upgrading hardware will be cheaper than refactoring.</p>

[{'answer_id': 41369, 'author': 'GateKiller', 'author_id': 383, 'author_profile': 'https://Stackoverflow.com/users/383', 'pm_score': 2, 'selected': False, 'text': '<p>Jeff and Joel discuss scaling in the <a href="https://blog.stackoverflow.com/2008/08/podcast-19/">Stack Overflow Podcast #19</a>.</p>\n'}, {'answer_id': 41371, 'author': 'Malik Daud Ahmad Khokhar', 'author_id': 1688440, 'author_profile': 'https://Stackoverflow.com/users/1688440', 'pm_score': 2, 'selected': False, 'text': '<p>Well there\'s this blog called <a href="http://highscalability.com/welcome-high-scalability" rel="nofollow noreferrer">High Scalibility</a> that contains a lot of information on this topic. Some useful stuff.</p>\n'}, {'answer_id': 41372, 'author': 'svrist', 'author_id': 86, 'author_profile': 'https://Stackoverflow.com/users/86', 'pm_score': 2, 'selected': False, 'text': '<p>Often the most effective way to do this is by a well thought through design where scaling is a part of it. </p>\n\n<p>Decide what scaling actually means for your project. Is infinite amount of users, is it being able to handle a slashdotting on a website is it development-cycles?</p>\n\n<p>Use this to focus your development efforts</p>\n'}, {'answer_id': 41373, 'author': 'Simon Johnson', 'author_id': 854, 'author_profile': 'https://Stackoverflow.com/users/854', 'pm_score': 5, 'selected': True, 'text': "<p>The only thing I would say is write your application so that it can be deployed on a cluster from the very start. Anything above that is a premature optimisation. Your first job should be getting enough users to have a scaling problem. </p>\n\n<p>Build the code as simple as you can first, then profile the system second and optimise only when there is an obvious performance problem.</p>\n\n<p>Often the figures from profiling your code are counter-intuitive; the bottle-necks tend to reside in modules you didn't think would be slow. Data is king when it comes to optimisation. If you optimise the parts you think will be slow, you will often optimise the wrong things.</p>\n"}, {'answer_id': 41386, 'author': 'Nathan Long', 'author_id': 4376, 'author_profile': 'https://Stackoverflow.com/users/4376', 'pm_score': 1, 'selected': False, 'text': '<p>One good idea is to determine how much work each additional task creates. This can depend on how the algorithm is structured.</p>\n\n<p>For example, imagine you have some virtual cars in a city. At any moment, you want each car to have a map showing where all the cars are.</p>\n\n<p>One way to approach this would be:</p>\n\n<pre>\n    for each car {\n       determine my position;  \n       for each car {  \n         add my position to this car\'s map;  \n       }\n    }\n</pre>\n\n<p>This seems straightforward: look at the first car\'s position, add it to the map of every other car. Then look at the second car\'s position, add it to the map of every other car. Etc.</p>\n\n<p>But there is a scalability problem. When there are 2 cars, this strategy takes  4 "add my position" steps; when there are 3 cars, it takes 9 steps. <b>For each "position update," you have to cycle through the whole list of cars - and every car needs its position updated.</b> </p>\n\n<p>Ignoring how many other things must be done to each car (for example, it may take a fixed number of steps to calculate the position of an individual car), <b>for N cars, it takes N<sup>2</sup> "visits to cars" to run this algorithm</b>. This is no problem when you\'ve got 5 cars and 25 steps. But as you add cars, you will see the system bog down. 100 cars will take 10,000 steps, and 101 cars will take 10,201 steps!</p>\n\n<p>A better approach would be to undo the nesting of the for loops.</p>\n\n<pre>\n    for each car {  \n      add my position to a list;  \n    }  \n    for each car {    \n      give me an updated copy of the master list;  \n    }\n</pre>\n\n<p>With this strategy, the number of steps is a multiple of N, not of N<sup>2</sup>. <b>So 100 cars will take 100 times the work of 1 car - NOT 10,000 times the work</b>.</p>\n\n<p>This concept is sometimes expressed in "big O notation" - the number of steps needed are "big O of N" or "big O of N<sup>2</sup>."</p>\n\n<p>Note that this concept is only concerned with scalability - not optimizing the number of steps for each car. Here we don\'t care if it takes 5 steps or 50 steps per car - the main thing is that N cars take (X * N) steps, not (X * N<sup>2</sup>).</p>\n'}, {'answer_id': 41390, 'author': 'Tim Howland', 'author_id': 4276, 'author_profile': 'https://Stackoverflow.com/users/4276', 'pm_score': 1, 'selected': False, 'text': "<p>FWIW, most systems will scale most effectively by ignoring this until it's a problem- Moore's law is still holding, and unless your traffic is growing faster than Moore's law does, it's usually cheaper to just buy a bigger box (at $2 or $3K a pop) than to pay developers.</p>\n\n<p>That said, the most important place to focus is your data tier; that is the hardest part of your application to scale out, as it usually needs to be authoritative, and clustered commercial databases are very expensive- the open source variations are usually very tricky to get right.</p>\n\n<p>If you think there is a high likelihood that your application will need to scale, it may be intelligent to look into systems like memcached or map reduce relatively early in your development.</p>\n"}, {'answer_id': 77257, 'author': 'Ed Lucas', 'author_id': 12551, 'author_profile': 'https://Stackoverflow.com/users/12551', 'pm_score': 3, 'selected': False, 'text': '<p>Ok, so you\'ve hit on a key point in using the "big O notation".  That\'s one dimension that can certainly bite you in the rear if you\'re not paying attention.  There are also other dimensions at play that some folks don\'t see through the "big O" glasses (but if you look closer they really are).  </p>\n\n<p>A simple example of that dimension is a database join.  There are "best practices" in constructing, say, a left inner join which will help to make the sql execute more efficiently.  If you break down the relational calculus or even look at an explain plan (Oracle) you can easily see which indexes are being used in which order and if any table scans or nested operations are occurring.</p>\n\n<p>The concept of profiling is also key.  You have to be instrumented thoroughly and at the right granularity across all the moving parts of the architecture in order to identify and fix any inefficiencies.  Say for example you\'re building a 3-tier, multi-threaded, MVC2 web-based application with liberal use of AJAX and client side processing along with an OR Mapper between your app and the DB.  A simplistic linear single request/response flow looks like:</p>\n\n<pre>\nbrowser -> web server -> app server -> DB -> app server -> XSLT -> web server -> browser JS engine execution & rendering\n</pre>\n\n<p>You should have some method for measuring performance (response times, throughput measured in "stuff per unit time", etc.) in each of those distinct areas, not only at the box and OS level (CPU, memory, disk i/o, etc.), but specific to each tier\'s service.  So on the web server you\'ll need to know all the counters for the web server your\'re using.  In the app tier, you\'ll need that plus visibility into whatever virtual machine you\'re using (jvm, clr, whatever).  Most OR mappers manifest inside the virtual machine, so make sure you\'re paying attention to all the specifics if they\'re visible to you at that layer.  Inside the DB, you\'ll need to know <em>everything</em> that\'s being executed and all the specific tuning parameters for your flavor of DB.  If you have big bucks, BMC Patrol is a pretty good bet for most of it (with appropriate knowledge modules (KMs)).  At the cheap end, you can certainly roll your own but your mileage will vary based on your depth of expertise.</p>\n\n<p>Presuming everything is synchronous (no queue-based things going on that you need to wait for), there are tons of opportunities for performance and/or scalability issues.  But since your post is about scalability, let\'s ignore the browser except for any remote XHR calls that will invoke another request/response from the web server.</p>\n\n<p>So given this problem domain, what decisions could you make to help with scalability?</p>\n\n<ol>\n<li><p>Connection handling.  This is also bound to session management and authentication.  That has to be as clean and lightweight as possible without compromising security.  The metric is maximum connections per unit time.</p></li>\n<li><p>Session failover at each tier.  Necessary or not?  We assume that each tier will be a cluster of boxes horizontally under some load balancing mechanism.  Load balancing is typically very lightweight, but some implementations of session failover can be heavier than desired.  Also whether you\'re running with sticky sessions can impact your options deeper in the architecture.  You also have to decide whether to tie a web server to a specific app server or not.  In the .NET remoting world, it\'s probably easier to tether them together.  If you use the Microsoft stack, it may be more scalable to do 2-tier (skip the remoting), but you have to make a substantial security tradeoff.  On the java side, I\'ve always seen it at least 3-tier.  No reason to do it otherwise.</p></li>\n<li><p>Object hierarchy. Inside the app, you need the cleanest possible, lightest weight object structure possible.  Only bring the data you need when you need it.  Viciously excise any unnecessary or superfluous getting of data.</p></li>\n<li><p>OR mapper inefficiencies.  There is an impedance mismatch between object design and relational design.  The many-to-many construct in an RDBMS is in direct conflict with object hierarchies (person.address vs. location.resident).  The more complex your data structures, the less efficient your OR mapper will be.  At some point you may have to cut bait in a one-off situation and do a more...uh...primitive data access approach (Stored Procedure + Data Access Layer) in order to squeeze more performance or scalability out of a particularly ugly module.  Understand the cost involved and make it a conscious decision.</p></li>\n<li><p>XSL transforms.  XML is a wonderful, normalized mechanism for data transport, but man can it be a huge performance dog!  Depending on how much data you\'re carrying around with you and which parser you choose and how complex your structure is, you could easily paint yourself into a very dark corner with XSLT.  Yes, academically it\'s a brilliantly clean way of doing a presentation layer, but in the real world there can be catastrophic performance issues if you don\'t pay particular attention to this.  I\'ve seen a system consume over 30% of transaction time just in XSLT.  Not pretty if you\'re trying to ramp up 4x the user base without buying additional boxes.</p></li>\n<li><p>Can you buy your way out of a scalability jam?  Absolutely.  I\'ve watched it happen more times than I\'d like to admit.  Moore\'s Law (as you already mentioned) is still valid today.  Have some extra cash handy just in case.</p></li>\n<li><p>Caching is a great tool to reduce the strain on the engine (increasing speed and throughput is a handy side-effect).  It comes at a cost though in terms of memory footprint and complexity in invalidating the cache when it\'s stale.  My decision would be to start completely clean and slowly add caching only where you decide it\'s useful to you.  Too many times the complexities are underestimated and what started out as a way to fix performance problems turns out to cause functional problems.  Also, back to the data usage comment.  If you\'re creating gigabytes worth of objects every minute, it doesn\'t matter if you cache or not.  You\'ll quickly max out your memory footprint and garbage collection will ruin your day.  So I guess the takeaway is to make sure you understand exactly what\'s going on inside your virtual machine (object creation, destruction, GCs, etc.) so that you can make the best possible decisions.</p></li>\n</ol>\n\n<p>Sorry for the verbosity.  Just got rolling and forgot to look up.  Hope some of this touches on the spirit of your inquiry and isn\'t too rudimentary a conversation.</p>\n'}]
['https://Stackoverflow.com/questions/41367', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/4376/']