Ars has an interesting perspective on the future possibilities of web sockets and the real-time applications made possible by this technology. MMO is a good example domain. Lots of concurrent users need simultaneous updates with as little latency possible. I'm trying to be careful with my words here - real-time isn't exactly attainable to the same degree as Skype or WoW. At least not with the currently-available combinations of server and client technologies for the web. The potential is most certainly there, but is it real-time MMO style domains we should chasing after with web sockets?
I would argue that it might be a little premature to dive-into such problems with web sockets as your weapon. Especially since these large scale problems already have solutions implemented that work quite well. Another hurdle facing web developers and their ambition to solve big programming challenges with web sockets is lack of browser support.
Factors that work against web socket technology are also it's strength. Why not use web sockets to make the current web a little more responsive? Why not give your users a sense of liveliness when they visit your web pages? Before web sockets came along — they're only now beginning to gain populatrity in the web development community — it was painful to make even the most basic information current. We're getting closer to doing this seamlessly now. The question is, where do we start?
The Static Web
Looking in the opposite direction from that of the MMO domain, let's think about static web pages. By static web pages, I don't necessarily mean flat HTML files sitting on a server somewhere, waiting for a user agent to request a copy. The static web can just as well be dynamically-generated web pages, assembled during request time from numerous sources. The static web is only static from the user's perspective. That is, they request a page, and once it arrives, it's dead. Nothing more than a copy of the real data with no potential to evolve and keep in tune with it's origin. You could keep your browser window open for a decade and watch the DOM elements collect dust.
Thinking about web pages this way really digs at the core problem that web socket technology addresses. We want our users to receive live data. When the real data that's stored in the database changes state, we want those changes available instantaneously. That means that any active web socket connection will receive new data, instructing the DOM elements in the client's browser to rearrange themselves. Sounds great, doesn't it?
Let's imagine that we had a framework that enabled us to keep content live like this. Now, who would this web socket framework benefit? Like most content on the web, this blog for example, there isn't much to gain simply due to the nature of the data. It gets written, published, maybe updated once or twice. Other than that, my blog data becomes stale shortly after it's published. Let's not confuse staleness with usefulness. Staleness means that other components that rely on fresh, or near real-time data, can't rely on it.
So having said that, if the vast majority of static web content out there has nothing major to gain from web socket technology, what does? I'm talking, of course, outside of the MMO domain here — how do we think about data that goes on the web in terms of liveliness?
Reshaping Data
If we're going to make good use of technology that allows us to publish changes to data as they happen, we should first look at the frequency of change. That is, how often would we be pushing out updates to the web browser? If the answer lies somewhere between once every couple minutes and once per second, your data is live and should be reflected in the user experience you provide. Another way to visualize how users deal with stale data is to picture them hitting the refresh button — their lifeline for new information.
The reality is, I think, that most information available in the static web universe follows a pattern shaped by the fact that users only have a one-time view of the data. We're not designing websites with the hope that users will simply hit refresh to synchronize with reality. Sure, we've got to accommodate this behaviour as it is the expectation — users want fresh data and there is a magic button built-in to every browser that will make that happen. But is that the best we can do for folks? Or can we raise the expectation that what they're looking at is reasonably accurate?
Doing so isn't trivial because we have to rethink what changes in state mean for the application. When data gets written to the database in your typical web application, that means nothing for most users. They might get a response, telling of the newly-created entity. But what does that mean for other views of the data model? Does it impact statistical views that someone in a cave might be staring at? Absolutely. Does it mean that the application should take notice of these changes in state and make relevant users sessions aware? You bet.
On top of all this talk about real-time MMO gaming, and events that should be pushed out to user sessions in an otherwise static web application, we're one step closer to making web applications the dominant platform. Developers target specific mobile and desktop platforms for a number of reasons, one of which, it's easier to get up-to-date data into the UI. I can see the gap between the two closing in — but before that happens, we need to somehow merge the static web and the live web. There is nothing wrong with the web the way it is today for displaying certain kinds of information. But we're now able to start taking seriously the notion of real-time data in domains where timeliness matters.
Tuesday, May 22, 2012
Tuesday, May 15, 2012
Flexible Business Policies
With any software system, there are business rules. Rules dictate what a user can and cannot do. The order in which they're allowed to submit data, the possible values the system is willing to accept from them, the state of the system before they're allowed to perform a specific action. The list goes on. Some might view business rules as a contract — a set of acceptable behaviours when interacting with software. Not only are these rules contractual, but they're also enforceable. One thing software developers try to do is to decouple the business rules from the actual code. Not only is this a best practice in terms of separating concerns — what the software does versus how it does it — it also provides a means to change the business rules without changing the software.
What this gives us is a set of policies, business policies that operate independently of the application we've built. When the policy changes, the behaviour of the software changes too. This all sounds great, having a complete separation of business concerns and implementation concerns. But what kind side-effects are we introducing when the business rules aren't interwoven throughout the code? Are we limiting what users can actually do with the software, or worse, are we introducing deadlocks into the system by giving business policies free reign?
Fundamental Policies
If we're to embed a work-flow policy engine into our code, perhaps a good starting point is looking at the basics. That is, what kind of questions can we ask about the overall state of the system? From there, we can ask if this is something we would want to hard-code, or allow as a parameter to the business end of things. For example, let's say I'm building a simple file upload interface. Let's also say that a requirement of the system is that there must be enough disk space to accommodate the new file. The first option: write some sanity-checking code that ensures there is enough disk capacity before the upload is allowed to start. The safe route — you'll never start an upload only to fail half way through.
Now for the second option. Let's say we want to continuously check for disk space as the upload is happening. That is, we don't want to forbid an upload because only 90% of the file will fit. Files are deleted all the time in this particular system we're building. That means there is a good chance the 10% of our required disk space will become available during the upload. This is something we would most certainly want to avoid hard-coding. Not only is this logic experimental, but since it is far from straightforward, it will likely impact other components in our system should we decide to implement it. Could we express this latter option as a business policy?
Let's go back to the first option for a moment, where we're simply checking for space before the upload starts. What if we were to implement this as a policy instead of codifying our logic? That depends, and this is a good question to ask because it forces us to validate our fundamental assumptions about how the system should work. Should the file uploader check once for disk space and fail immediately? How likely is that to change due to other factors in the system and due to user feedback? Apprehension in any one of these areas lead us to rethink our assumptions about more than just the file uploader — how it is connected to other components — can a more elaborate work-flow be supported without major architectural change?
What I find most useful about these mental exercises on what should be hard-coded and what shouldn't is the evolutionary path that you're prepared to support. Maybe a file uploader that checks for disk in-flight is far-fetched and unlikely. But it opens the door to other potential changes and how hard-coding certain scenarios might become a problem. The opposite is also true — too much embedded business policy. Just like the hard-coded logic means stuff is hard to change, so to is overloading code with external business logic.
Rigid Policies
At this point in the development game, we've answered some of our fundamental questions about business policies, and where they're beneficial to the long-term evolution of our software. That's half the battle. The other half is the policies we're designing and how they work compared to coding the same logic using a programming language. Is it really all that different? Can we escape some of the pitfalls associated with programming languages and their paradigms of expressing logic? And this is where problems with rigid business rules rear their head — when we're making an assumption about reduced complexity.
Take rigid rules set forth by a business policy as an example. By rigid, I'm talking about validating the state of something to an exact value — not within a range, or almost equal, but dead-on accurate. Like when the database must be connected. There is no in-between for these types of rules, they either pass the test or they don't. These types of business policies are easy to create and plug into slots we've deemed suitable within the code base. Perhaps a little too easy. Too much freedom for exacting requirements in business work-flow leads to scenarios that are very difficult to debug.
Rules that require a condition of system state are fine on their own, but the whole point of adding a business policy engine to the project is to afford the flexibility of building work-flows incrementally. Stacking one rule on top of another. Instead of achieving flexibility, we're building up a disconnect between the code and the business engine. When everything works, we still have that degree of separation between the pure software components, and the written rules of the business domain. So, if we have fundamental rigidity in our policies, when something does go wrong, it is very difficult to sort out.
Achieving Flexibility
There are two ends of the spectrum when in comes to implementing business policies. The one end gives rules that must match the state of the system exactly in order to resolve as true. The other views business rules as a guidance tool. That is, business rules simply point certain flows of control in the right direction. Consider the business practice of online retailers providing their shoppers with relevant product suggestions. This type of behaviour fits the business policy candidacy quite nicely because it doesn't require exact values that overly-restrict the actions of users. A store needs flexibility, an easy way to tweak this logic.
Business policies shouldn't be too low-level or even expect high-accuracy. There is no real harm in creating plain-old software components that do these types of calculations. They're really good at it. What they're not so good at is taking a pure business principle and applying it within the confines of the software system. Not from an evolutionary perspective at least. It takes software development effort and that equates to time and money. Business policies are a nice way to experiment with different work-flow implementations to gain a competitive edge.
What this gives us is a set of policies, business policies that operate independently of the application we've built. When the policy changes, the behaviour of the software changes too. This all sounds great, having a complete separation of business concerns and implementation concerns. But what kind side-effects are we introducing when the business rules aren't interwoven throughout the code? Are we limiting what users can actually do with the software, or worse, are we introducing deadlocks into the system by giving business policies free reign?
Fundamental Policies
If we're to embed a work-flow policy engine into our code, perhaps a good starting point is looking at the basics. That is, what kind of questions can we ask about the overall state of the system? From there, we can ask if this is something we would want to hard-code, or allow as a parameter to the business end of things. For example, let's say I'm building a simple file upload interface. Let's also say that a requirement of the system is that there must be enough disk space to accommodate the new file. The first option: write some sanity-checking code that ensures there is enough disk capacity before the upload is allowed to start. The safe route — you'll never start an upload only to fail half way through.
Now for the second option. Let's say we want to continuously check for disk space as the upload is happening. That is, we don't want to forbid an upload because only 90% of the file will fit. Files are deleted all the time in this particular system we're building. That means there is a good chance the 10% of our required disk space will become available during the upload. This is something we would most certainly want to avoid hard-coding. Not only is this logic experimental, but since it is far from straightforward, it will likely impact other components in our system should we decide to implement it. Could we express this latter option as a business policy?
Let's go back to the first option for a moment, where we're simply checking for space before the upload starts. What if we were to implement this as a policy instead of codifying our logic? That depends, and this is a good question to ask because it forces us to validate our fundamental assumptions about how the system should work. Should the file uploader check once for disk space and fail immediately? How likely is that to change due to other factors in the system and due to user feedback? Apprehension in any one of these areas lead us to rethink our assumptions about more than just the file uploader — how it is connected to other components — can a more elaborate work-flow be supported without major architectural change?
What I find most useful about these mental exercises on what should be hard-coded and what shouldn't is the evolutionary path that you're prepared to support. Maybe a file uploader that checks for disk in-flight is far-fetched and unlikely. But it opens the door to other potential changes and how hard-coding certain scenarios might become a problem. The opposite is also true — too much embedded business policy. Just like the hard-coded logic means stuff is hard to change, so to is overloading code with external business logic.
Rigid Policies
At this point in the development game, we've answered some of our fundamental questions about business policies, and where they're beneficial to the long-term evolution of our software. That's half the battle. The other half is the policies we're designing and how they work compared to coding the same logic using a programming language. Is it really all that different? Can we escape some of the pitfalls associated with programming languages and their paradigms of expressing logic? And this is where problems with rigid business rules rear their head — when we're making an assumption about reduced complexity.
Take rigid rules set forth by a business policy as an example. By rigid, I'm talking about validating the state of something to an exact value — not within a range, or almost equal, but dead-on accurate. Like when the database must be connected. There is no in-between for these types of rules, they either pass the test or they don't. These types of business policies are easy to create and plug into slots we've deemed suitable within the code base. Perhaps a little too easy. Too much freedom for exacting requirements in business work-flow leads to scenarios that are very difficult to debug.
Rules that require a condition of system state are fine on their own, but the whole point of adding a business policy engine to the project is to afford the flexibility of building work-flows incrementally. Stacking one rule on top of another. Instead of achieving flexibility, we're building up a disconnect between the code and the business engine. When everything works, we still have that degree of separation between the pure software components, and the written rules of the business domain. So, if we have fundamental rigidity in our policies, when something does go wrong, it is very difficult to sort out.
Achieving Flexibility
There are two ends of the spectrum when in comes to implementing business policies. The one end gives rules that must match the state of the system exactly in order to resolve as true. The other views business rules as a guidance tool. That is, business rules simply point certain flows of control in the right direction. Consider the business practice of online retailers providing their shoppers with relevant product suggestions. This type of behaviour fits the business policy candidacy quite nicely because it doesn't require exact values that overly-restrict the actions of users. A store needs flexibility, an easy way to tweak this logic.
Business policies shouldn't be too low-level or even expect high-accuracy. There is no real harm in creating plain-old software components that do these types of calculations. They're really good at it. What they're not so good at is taking a pure business principle and applying it within the confines of the software system. Not from an evolutionary perspective at least. It takes software development effort and that equates to time and money. Business policies are a nice way to experiment with different work-flow implementations to gain a competitive edge.
Wednesday, May 2, 2012
Controlling Wijmo Context Menu Display
The Wijmo menu widget can do some really neat things. For one, it is flexible in that it can behave as a regular navigational menu, or as a context menu. The context menu is especially handy and bridges a rather large gap in jQuery UI. It isn't without it's limitations though.
Wijmo menu items can change dynamically. We would put this capability to use when menu items should be hidden due to the state of another object, for example. The menu API allows the developer to easily add and remove items. However, the challenge lies with controlling whether or not the context menu should be displayed at all. For instance, if all menu items have been removed, for one reason or another. This is where we need to take precaution because the menu has no built-in display control.
Example
Let's look at a trivial example where can add and remove items from a context menu dynamically. This includes the possibility of emptying the menu, at which point, it shouldn't be displayed.
The HTML...
The Javascript...
This will create three buttons. The first will display the context menu when clicked. The second button will add a new item to the context menu, and the last button will remove an item. The intent behind the add and remove buttons is to control how the context menu is displayed. You can remove items until the menu is empty. At this point, the context menu will not display until you add a new item.
Explanation
The key take-away here is the click event on the show menu button. This event handler is how we're able to control the context menu display based on some logic. In our case, we don't want to display the menu if there aren't any items in it. But I'm sure there are other use cases where overriding the context menu display would be beneficial.
The other thing to note is how we're actually stopping the context menu from displaying. We're calling event.stopImmediatePropagation(). Since this event handler is the first one executed when the button is clicked, no other handlers will be executed if the menu is empty. This includes the context menu trigger.
Wijmo menu items can change dynamically. We would put this capability to use when menu items should be hidden due to the state of another object, for example. The menu API allows the developer to easily add and remove items. However, the challenge lies with controlling whether or not the context menu should be displayed at all. For instance, if all menu items have been removed, for one reason or another. This is where we need to take precaution because the menu has no built-in display control.
Example
Let's look at a trivial example where can add and remove items from a context menu dynamically. This includes the possibility of emptying the menu, at which point, it shouldn't be displayed.
The HTML...
<body>
<button id="btnmenu">Show Menu</button>
<button id="btnadd">Add Item</button>
<button id="btnremove">Remove Item</button>
<ul id="menu">
<li><a href="#">Item 1</a></li>
<li><a href="#">Item 2</a></li>
<li><a href="#">Item 3</a></li>
</ul>
</body>
The Javascript...
$(document).ready(function () {
$('#btnmenu').button().click(function (event) {
if ($('#menu').find('li').length === 0) {
event.stopImmediatePropagation();
}
});
$('#btnadd').button().click(function (event) {
var menu = $('#menu'),
itemCount = menu.find('li').length,
itemText = 'Item ' + (itemCount + 1),
itemLink = $('<a>').attr('href', '#').text(itemText);
menu.append($('<li/>').append(itemLink))
.wijmenu('refresh');
});
$('#btnremove').button().click(function (event) {
$('#menu').find('li').last().remove();
});
$('#menu').wijmenu({
orientation: 'vertical',
trigger: '#btnmenu'
});
});
This will create three buttons. The first will display the context menu when clicked. The second button will add a new item to the context menu, and the last button will remove an item. The intent behind the add and remove buttons is to control how the context menu is displayed. You can remove items until the menu is empty. At this point, the context menu will not display until you add a new item.
Explanation
The key take-away here is the click event on the show menu button. This event handler is how we're able to control the context menu display based on some logic. In our case, we don't want to display the menu if there aren't any items in it. But I'm sure there are other use cases where overriding the context menu display would be beneficial.
The other thing to note is how we're actually stopping the context menu from displaying. We're calling event.stopImmediatePropagation(). Since this event handler is the first one executed when the button is clicked, no other handlers will be executed if the menu is empty. This includes the context menu trigger.
Subscribe to:
Posts
(
Atom
)
