JavaScript at Scale
上QQ阅读APP看书,第一时间看更新

Scaling users

The most important user is us—the development organization. While our mission is to keep our users happy by delivering software that scales, we need to keep ourselves happy too. And that requires a viable business model. The reason we care about this is because different models mean different approaches to acquire new users, and manage existing users. From there, the complexities of scaling our user base get deeper. We need to consider how our users are organized, how they use our software to communicate with one another, how to provide support, collect feedback, and collect user metrics.

Viable business models for JavaScript applications range from deploying a free service that's ad-supported, to a private, on-premise deployment of our software, where we collect license fees. Deciding which approach is right for the organization is likely out of our hands. However, it's our responsibility to understand the chosen business model and relate it to the current and future users of our software.

The business model can grow quite complex. For instance, organizations will often start off with one approach that's clear cut and keeps users happy, while meeting business expectations. However, as the organization grows and matures, the once coherent business model is obscured into something that's less approachable, and has unpredictable results for our architecture. Let's take a look at some of these business models and how each impacts the scalability of our user base.

License fees

Software licensing is a complex topic, one that we're not going to explore in depth here. What's important is simply whether or not we're relying on licensed software as our business model. If we are, then we likely have other organizations deploying our JavaScript applications on-premise. It's unlikely that we'll have inpiduals purchasing licenses. Not impossible though—it depends on the nature of the software. The likely case with selling licenses is that our software will be privately deployed by multiple organizations.

There are two interesting scaling properties to consider with this business model. Firstly, there's a fundamental limit on the number of users within a given organization. While organizations can be large, and we can sell to multiple large organizations, the common case is to have fewer users overall with a licensed model. Secondly, each organization has different needs in terms of customizations. This involves configurability, user organization, and so on. We're more likely to experience requests for these types of changes or enhancements using a licensed model.

So, while there're not as many users to support, the nature of supporting them is more complex due to the structure of the organization using our software, and hence difficult to scale. Dependency management in these environments can be challenging as well, due to restrictions that determine how our software is able to scale. In other environments, these restrictions are more lax.

Subscription fees

Subscriptions are recurring fees we collect for the use of our software. This approach costs our users less, most of the time. It's also a more flexible business model in that it can easily apply to software that's deployed on-premise, and software that's deployed publicly.

Since it's cheaper for organizations to deploy subscription-based software rather than license-based ones, we're more likely to reach more organizations. Mind you, these are organizations pided into departments, each with their own budgetary constraints.

In terms of scale, however, the challenge with subscriptions is similar to the challenge faced with licenses, that is, complex customization requests. If subscriptions are likely to get us more on-premise deployments and likely more arcane feature requests. Another scaling problem facing the subscription approach is customer retention. Users aren't going to continue paying subscription fees if value isn't continuously delivered.

So if we go the subscription route, we need to scale up our efforts in delivering new features that justify the recurring subscription costs for our users.

Consumption fees

Another business model for software is consumption, or, pay-as-you-go. This is an appealing model for users since they're not paying for resources they don't use. Of course, this doesn't suit every application. What if there are no meaningful resources for users to consume? What if we're running our application in a way that resource consumption is of no concern to us?

In other cases, the resource usage is glaringly obvious. Maybe the user performs some computationally-expensive task, or stores a lot of data for a period of time. In these cases, the consumption model makes perfect sense, for both us and the user. Users that consume less, pay less. User behavior can be erratic, with spikes of consumption. However, these events are brief, relative to the rest of the time they're using our application.

The scaling challenge we face with this business model is that we need good tools in addition to the core aspects of our application. First, we need a tool that measures and records consumption. Second, we need tools to accurately portray these consumption metrics, often visually. Depending on what users are consuming, and what level of integration we're expecting, there might be a third-party component to consider.

Ad-supported

Another option is to deploy our application to the public internet and use display advertisements for revenue. These are free applications, and hence more likely to be used. On the other hand, advertisements are a big turn-off to many people, which counteracts the appeal of "free".

Perhaps the goal when using this approach, rather than ad revenue, is generating mass usage. The two go hand-in-hand actually, more users means more ad revenue. However, mass adoption of an online JavaScript application can catch the attention of investors. So lots of user accounts, by itself, has merit.

These types of applications are different from those that follow other business models, in how they scale. Applications that gain mass appeal on the internet solve different problems for different user personas. Following this model means we need to have reach, and to scale our reach means lowering the barrier to entry. Our focus, while using this business model, is on ease-of-use and social validity.

Open source

The final business model for us to consider is open source. Don't laugh; open source software is vital to the functioning of the web. It's highly unlikely that our JavaScript application doesn't use any open source components. It's more likely that we're only using open source components. But why do people spend their valuable time developing tools for everyone else to use, even their competition?

The first misconception here is that folks are just sitting around, unemployed, building open source software for the rest of us to use. The fact is, most of the tools we'll use are built by people in strong positions at companies that use the same technologies we do. They may have even started the open source project to solve a problem for the company—to provide a missing tool in their development process.

The second misconception is that we're helping out our competitors by starting up, or contributing to, open source projects. It's not possible for us to single-handedly put ourselves in a worse position than our competition via open source software. By other measures, yes, it's absolutely possible to help out our competition by hurting ourselves.

On the other hand, open source projects can be good for an organization. They have to be effective projects; something that's usable and generic. If it grows legs, we're creating new stakeholders in technology that we rely on, and that's a good thing. The community that surrounds an open source project is invaluable. While open source by itself can't support an organization, there's no escaping the fact that it's an integral part of any JavaScript application business model.

Groups and rolesGroups allow us to classify our users. Think of the role as a user type. This is a powerful abstraction, because it allows us to generalize aspects of features by role type. For example, instead of checking conditions based on user properties, we check them based on role properties. It's a lot easier to move a user from one role to another, than to modify our logic.

Figuring out user roles and how they translate into group implementations is a tricky subject. The only thing we can count on is having to shuffle around the organizational structure of our users. So, making the grouping mechanism as generic as possible is our first goal. This has trade-offs too—anything that's completely generic has negative performance implications.

Some grouping decisions will be obvious up front. Like whether users are aware of other users in the system or not. If they are, we can start drilling into the specific questions around how users communicate with one another using our application. Again, this may be obvious based on the types of features our application has. The business model we're following influences our user management design as well. If we're selling software licenses and likely to be deployed on-premise, then we can expect lots of varying needs for user roles, and the subsequent grouping implementation. If we're deployed publicly on the internet, grouping is less of a concern—we can probably choose a simple approach in favor of performance, for example.

As our software grows more complex, as we add more features and bring on more customers, we'll start to see the need to segregate parts of our application. That is, we'll need to tie-down certain features based on access control permissions. Rather than having different user roles, install separate software systems; it's easier for them to have a single system with users, groups, and access control.

This has implications for us as JavaScript architects because once we start down the access control path, there's no turning back. From that point forward, we have to be consistent—every feature needs to check for the appropriate permissions. Further complicating matters, is that if we're grouping users this way, we're probably going to have to group other entities of our system in a similar fashion at some point. Which only makes sense, especially to the end user – this group of things is accessed and used by that group of users.

Communicating users

Another aspect to consider with regard to users, and their relationships with one another, is the communication channels available to these users. Do they explicitly pick and choose other users to communicate with? Or is the communication more implicit? An example of the latter might be a user from the same group as us, looking at a chart. This chart is generated based on data that's put into the system by other members of the group. Is it worthwhile to think about these sorts of implicit communication channels in addition to the explicit ones?

The nature of our application determines which communication channels are open to our users. It might also depend on the users themselves. Some applications have users that need to get in there, and expertly perform a task—communicating with other users is unnecessary. On the other hand, we might find ourselves developing something that's a little more social-minded. In fact, we might even depend on the services of an external social network.

If we're going to rely on third-party user management, social networks or otherwise, we have to be careful how tightly coupled we become with these services. In terms of scale, using third-party authentication mechanisms may have social bonus features we want—especially considering that most users will love the fact that they don't need yet another account to use our application. Scaling this approach to user management becomes a problem from other perspectives once we start implementing new features, where third-party integration is complex. For example, a photo editing application might scale better using a Facebook login, since that's where most users' photos originate.

Users are going to find a way to communicate with one another if our application is useful or fun to use. We can fight it, or we can leverage user communication as a tool to help us scale. That is, scale the transparency with which our users can point their peers to something useful, that they would otherwise have to go and dig-around for.

Support mechanisms

It's great to have our JavaScript application just work. Even when everything's going according to plan, we've deployed and there are no bugs, we have to support the cases where the users have no idea how to use something. Or they've performed some action they probably shouldn't have. Or where one of the other ten million usability issues are relevant, and swift rescue is in order.

Our support mechanism not scaling can grind our business to a halt. So, in addition to our software scaling well, we need to think about how the user support systems are going to scale alongside it. Support can be tightly integrated, or farmed out to third-party software and personnel.

It's better if users don't need support to use our software. That's why we design with usability in mind. We walk through the various user experiences, often with experts and/or actual users, and integrate design for them in our software. This is the most obvious thing we can tackle when it comes to supporting our users. Because if we can do this, through usability design, then we can eliminate a large portion of the likely support issues we'll face as we scale.

Regardless, we still have to assume that we're not thinking of the support cases that will inevitably pop up after deployment. Users are inquisitive. Even if everything is going fine, they still might have questions. So we can't really say, "we've designed a great user experience for you and everything's working, so go away". We need to be responsive with our users' questions and concerns. Because the second we're being dismissive about inquiries, we're failing to scale our application.

Can our JavaScript components help with supporting our users? If that's what we want, absolutely! In fact, contextual help is probably the most effective. If a user has a question about a particular component, and they see a help button, right there within the problematic component, then they can use that to submit their question. On the receiving end of the support question, there's less confusion. We know exactly what the user is trying to do, and spending time creating the context around the issue is no longer necessary.

This is definitely easier said than done and has other scaling implications for us. These contextual help systems aren't effort-free. And should we decide to go that route, we' would have to consider contextual help with every feature we implement. Can this scale alongside everything else we're doing?

Another approach we might want to consider is a knowledge base with information from the organization creating the software, and also from those that use it. Those using it for a particular purpose are apt to have better answers than us, and these answers are super-valuable. Not only to users looking for answers, but also to us.

Feedback mechanisms

Is feedback really worth differentiating from support? Support is definitely feedback. If we pay attention to the various support issues we encounter over time, we can transform it into feedback and use this information as feedback. However, it's still worth differentiating the two forms, because the user is in a different frame of mind. While experiencing a support issue, there's frustration, ranging from mild to intense. This user doesn't care about improving the product now—they need to get their job done.

On the other hand, users who've used our software for a while grow acutely aware of the inefficiencies of their workflow. Collecting this type of feedback is crucial. How do we get it? One option is supplying a feedback button in the application, as we would with a contextual support button. Another option is to let a third-party handle feedback collection. As with support, automating the context is always better for us when it comes to understanding what the user is talking about without spending too much time on it.

The key with feedback is keeping customers engaged. Not everyone who uses our software is going to share their thoughts with us. But some no doubt will—even if they're just venting frustration. We have to respond to these in order to establish a dialog. Users who supply feedback like this want us to respond to them. And it's in the ongoing conversation with these users where the product improvements emerge, not in the brilliant ideas initially submitted by users.

As our user base grows, can we keep up and stay responsive to user feedback? Obviously this is a challenge, given everything else that's on our plate, dealing with our application's growth. It's one thing to create dialog around a given piece of user data, but it's another to act on that feedback. Suppose we've enabled great feedback mechanisms, embedded in our software. We will have to turn this into actionable work at some point. So, we need to think about how our process of generating requirements based on user feedback scales. If it doesn't, and user feedback is never acted upon, they'll bail and we will have failed to scale.

Notifying users

JavaScript applications need to display notifications to its users. These can be fairly straightforward to implement, especially if we're mainly concerned with responding to user actions. For example, when users do something, it results in an API request to the back-end. We will want to display a notification to the user, indicating that the action has succeeded or failed. These notifications look the same across the application—we can use the same tool for most, if not all, notifications.

Notifications are easy to forget about in terms of designing a scalable JavaScript architecture. It's a big topic—there are contextual notifications, general notifications, and notifications that take place when the user is offline. The latter generally means that something has been emailed to the user, prompting them to log in and take action if need be.

The contextual notifications are probably the most important, as they supply feedback to the user on something they're currently doing. This is challenging to scale because we have to ensure that these types of notifications remain consistent across the user interface, for all types of entities. The more general notifications take place as a result of something happening in the background.

Some resource that belongs to a user may have changed state, either expectedly or unexpectedly. Regardless, the user probably wants to know about these events. Ideally, if they're logged in and using the system, then a generic notification will reveal itself. However, we may want these types of notifications emailed to users as well.

The challenge with any notification system is volume. If there are a lot of users, and they're fairly active, a lot of notifications will need to be generated and delivered. This will no doubt interfere with the performance of other components in our code. We're also faced with the configurability that comes with notifications. We'll never get the notifications right for all of our users, so we'll need some degree of notification tuning. The right level that scales our application is up to us JavaScript architects and developers.

User metrics

The best way to approach the question of how users interact with our software is through data. Certain data points cannot be guessed at or manually collected. This is where we need to rely on tools that automatically collect user metrics as they interact with our software. With the raw data in place, we're well-equipped to analyze what we see, and make decisions.

While it makes sense to automate this task, the task may not be necessary in the first place. It may only be worthwhile to collect user metrics when we're really unsure about the future direction of a given feature, or when we want further insight on what work to prioritize. A lot of the time, we can get these answers without much effort, and 'there'll certainly be no need for analytical tools. We may not even be permitted to collect such data if we've deployed on-premise somewhere.

There's a ton of good third-party metric collection tools available. These are especially helpful because they ship with a lot of the reporting we need. And a lot that we don't. There's also the question of how tightly integrated we want our third-party components. There's always a chance that we would need to turn such a feature off. Or, at least change where such data is stored.

There are a number of uses for this data other than just input for product direction decisions. Our code can take user metric data and reflectively improve the experience. This could be something as innocent as making suggestions on what to do next, based on past events. Or we could get really fancy and make efficiency optimizations based on this data. It all comes down to the common case of what our users want. Figuring out what our users want is a scaling problem in and of itself, because as we grow, we acquire more users who all want different things. User metrics could turn out to be a helpful tool with which to combat this issue.

Scaling users example

Our software firm is developing an online lending application. It's fairly straightforward; there's not a lot of moving parts in the front end. The applicant first creates an account, and then can apply for a new loan and manage existing loans. The business model of this application is consumption-based. We earn revenue through interest on the loans, so the more the loans consumed, the more we earn.

The obvious scaling influencers are user volume and ease of use. Part of our value proposition is low interest on small loans. There should be very little overhead for the users when applying for a new loan; minimal input required, and minimal wait time for the loan application to succeed or fail. This is our highly focused vision for delivering value, and some of more apparent scaling influencers we'll be up against.

Let's think about some of the more subtle implications of our application with regard to scale. Given the type of application this is, we're unlikely to see requests for social functions. For the most part, the user can be treated as a black box; they're in their own little universe when using our application. Since ease of use is very important to us, and our application has few moving parts, support and feedback are unlikely factors when it comes to scale. We can't eliminate support and feedback, but our focus on those areas can be minimal.

On the other hand, we need to market our service and we really have no idea what our customers are getting loans for, what are the most popular repayment schedules, and so on. For this, we can probably deliver a more effective market message, as well as improve our overall user experience. The implication here being that collecting meta data about our application is a big deal. Since we're after large user numbers, the implication is that we'll need to store lots of meta data. We'll also have to design each feature in such a way that we can collect metrics and store them for later use, which complicates the design.