Wednesday, March 28, 2012

Naming Things

How do we tell two people apart?  That is, how do we know that Fred is a different person than William?  An easy way to perform this differentiation is by comparing their names - Fred is a different handle than William - no need for deeper comparisons.  This is a great feature of names.  They're a shortcut for differentiation among things that are of the same classification, in this case, people.  But we also need a method to identify these classes of objects, these classes need names too - like humans, dogs, and laptops.  The two naming activities are similar, and yet they present two very different problems.

Classification names, by their very nature, refer to many objects.  Or more accurately, instances of these classifications.  If you've got several instances, you need a way to tell them apart.  Sure, we could examine, in fine detail, the differences between two instances of "dog", but it's easier to just learn that the brown dog's name is Bark and the white dog's name is Bite.  And therein lies the problem with naming things in a global context - my pet's name carries much meaning for myself, my family, probably my neighbors too, but outside of that tightly-knit group, Bark is just another dog.

Naming instances in computer programs is subjected to this same loss of meaning outside of a localized context.  What is that context exactly?  It could be any number of things, but I think it mostly becomes relevant in large software applications where in a large population of instances, the names attached to them really lose some of their identification basis.  Is there a need to attach meaning to individual instances in large scale software architectures?  Or can we get by implementing pools of anonymous instances, their existence a mere side-effect of a larger cause?

Why Instances Have Names
Writing software is a telling experience when it comes to understanding why and how things get named. When you really think about it, a large part of your responsibility as a software developer is devising meaningful names.  You instantiate an object in your code.  Further down in the editor, you tell that object to do something, or maybe you change the state of that object.  From very early on, we're told - again and again - use meaningful names.  That acumen still helps me now, as it did back when I was learning the fundamentals.  Instance names shed light on the attached attributes and methods.  Literally, these methods need a context in which to operate - the instance.  Think of the name as the same sort of required context required for our programmer's mind to comprehend how this object works.

There is something to naming instances that has an almost evasive quality to it. And that quality is giving something a good meaningful name that'll help my brain understand it when I return several hours later is hard.  It isn't just a matter of using real words as opposed to a letter and a number, obj1, but using actual words that reflect several intangibles about the instance, at a glance.  And this really is a powerful code-writing tool.  It really does save time.  If a good name prevents you from having to second guess how to use that object, you've just saved yourself a matter of seconds.  Doesn't sound like much, does it?  But it's the cumulative effect we're after.  It's the comfortable confidence we need to be productive in programming something useful, not constantly verifying our assumptions.

Giving an instance of a particular classifier a meaningful name is difficult enough without having to give many instances good names.  And this is where the scaling factor comes into play.  As our software systems grow more complex, we're going to have more instances created within.  There is a simple limit to how meaningful a name can be in a large population.

Scaling With Anonymity
What of instead of giving instances names, we gave them an arbitrary identity? Well it turns out we do this already.  In programs where we have a list of objects, we can refer to individuals by their index.  More commonly perhaps, we only reference instances indirectly through iterative patterns.  By this I mean iterating over a set, and interacting with each object in that set by unconditionally calling a method or performing more sophisticated logic.  The point is that when we designed this iterative behaviour, we didn't visualize an instance of a class - we wanted something done to a group of things.  So whenever we perform iterative behaviour like this over a set, we're using an instance that we didn't have to directly identify. We might have given the set itself a name, but we're using it to simulate a population of objects instead of having to uniquely identify each.

There are many places in code where we can get away with anonymous objects - with no direct reference to them.  Such as with sets, we might have behaviour that interacts with a single anonymous instance.  For example, maybe you've designed a method that expects an object of a particular type of interface.  This method might accept the instance as a parameter, or it might create the instance and destroy it after the work is done.  Regardless, it's then interface that matters, not the individual's identity.  In smaller contexts, such as within methods, it's easier to give short-lived instances meaningful identities since they're not competing for the programmer's attention.

But what about the interfaces themselves?  The classes that define how instances will function when they come to life?  I'm afraid naming classes and interfaces are not immune from the issue of naming things in large systems.  When a system gets bigger, we're naturally going to require more classes and interfaces.  The alternative is to try and stuff more of the responsibility into already-existing classes which doesn't help anyone.  We could try and solve the problem by defining anonymous behaviour - as we would with instances.  And therein lies the challenge. With anonymous instances, we can at least gain some perspective into what they are, or why they exist at a particular point in time.  That is, we can infer their class that made them what they are.  If you have an anonymous classifier that dictates how a thing operates, how can you reason about it?

We only have the ability to partially solve the naming problem in software design. There comes a point when you're simply moving the problem or creating a new one. Names hold meaning for us humans, but we have fundamental limits in how many names we can manage mentally.  It's an interesting problem, one that I'm confident will become more prevalent in the near-term.

Thursday, March 15, 2012

Web Sockets and Statelessness

The web works better when it's stateless, so the theory goes.  Stateless meaning that the client and server are largely decoupled from one another.  When applications are stateless, I can start a session on one computer, do something, and start another session elsewhere without worry.  Put another way, in the context of web applications, we're talking about stateless clients — all the application data resides on the server.

Statelessness matters because it's how we're able to scale to many concurrent users. This would be a daunting task if every action the user performed was managed by the server.  And so the web scales through simplicity — transferring the state of applications over HTTP.

Now we're seeing new protocols for how web application clients communicate with the server.  You want to use web sockets when interactivity is important — when updates in application state are unpredictable and thus difficult to publish over HTTP.  Intuitively, we'd like to use an abstraction that keeps the communication channel with the server open and listens for incoming data.  What, if anything does that mean for statelessness and how well will it scale, if at all?

When I first started experimenting with web socket technology, I was balked at the prospect of passing state back and forth rather than in a single direction.  But once you start using web sockets, it's really not that far a stretch from the tradition of HTTP.  It's just a communication protocol, and we can still apply RESTful principles to it.

Ask Now, Answer Later
A key advantage of web socket abstractions is the ability to ask a question, and not have to wait around for the answer.  If you need to get a list of objects, you issue a the command to fetch those objects over a web socket.  The web socket connection, at an indeterminate point in time after the command was issued, will receive the list of objects. The client's web socket connection passes this data into the Javascript code that can handle it however it wants.

What does this mean for the application running on the server that has to eventually respond to these socket requests?  Is this new technology somehow fixing a bottleneck in how requests block others from being fulfilled.  Not exactly.  Traditional HTTP requests only appear as though the server is actually spending significant effort in satisfying your request when in fact it's probably handling many requests simultaneously.  Well, I'm sure there are plenty of cases where there are longer-running requests that may actually affect the duration of others in the system.  However, these HTTP requests need a response in order to complete the workflow.  HTTP requests expect to be acknowledged somehow. Sockets, on the other hand, we can fire and forget.

Once a web socket requests lands on it's target server infrastructure, it goes about it's chores like any other client-server request.  It even responds to the client.  How this is actually accomplished largely depends on the web application framework you're using. For example, maybe the incoming web socket request spawns a new handler thread, within, the connection is available for writing back to the client.  Or, maybe you're not given any sort of client connection you can update as simply as a file object.  Maybe you have to go find it based on the request's session.  The end result, of course, means that you're no longer dealing with the traditional request handler abstraction where you can forget about the client once you've honoured your duties.  And this can cause a challenge in complexity.

With the flexibility that web sockets afford an application come new obstacles that we're not overly-concerned with, if at all, in our more traditional HTTP applications.  Once you've managed to wrap your head around the never-ending-connection philosophy, you'll start to realize that these sockets really do solve some ugly work-arounds that would otherwise need band-aids in HTTP land.  For instance, a command issued by the client might want to send sparse feedback — with a second or two in between.  This type of thing one can do blindfolded with web sockets.  It's the other little hindrances that'll make for an interesting experience — like softening of the command-response architecture rules.  Correspondingly, the stateless style of application we're used to building suddenly becomes foreign to us.

State Delivery
RESTful architectures push for statelessness by transferring the current state of data over the wire and to the client.  There is no such thing as state that remains in the web browser, aside from what the user is currently viewing or interacting with.  So my nagging concern about web sockets has always been along the lines of, how can we achieve something similar to stateless user interfaces?  I'm guessing I'm not alone when I don't want to throw out my learned experience with designing resilient systems that scale based on the principle of statelessness.

I've now come to understand that this is in fact not the case — web sockets aren't out to destroy our grounded beliefs in the command-response architecture.  No, web sockets are simply a delivery mechanism whereby state is transferred to some agent listening for it.  Not that different from HTTP, only improved for certain situations.  Like when state changes rapidly — more than once during a single command.  We need an intuitive method of transferring these changes in state back to the client without shooting ourselves in the foot with traditional HTTP modes.

I would say the frequency of state changes in your application domain will serve nicely as an indicator of how necessary web sockets are.  If it is frequent enough, perhaps web sockets are the answer.  Perhaps it'll make developing the using interface code that much easier by not having to result to polling techniques.  Because when you start implementing polling yourself, you're emulating the user hitting the refresh button.  If it seems silly to you that the user sit in her chair and click refresh constantly, it may be time to consider building with an abstraction better aligned with the model your data is asking for.

Monday, March 5, 2012

Data Recognition

We all recognize things, objects familiar to us.  Familiarity is a comforting phenomenon — it tells us we've been here before and we can make certain assumptions.  It's when we encounter the unfamiliar — the unrecognizable — that we begin to have second thoughts.  How we get stuff done, our jobs, our daily routines, it's all been done before.  When we learn something new — either at our job or something we've set out to do based solely on curiosity, we're building up our repertoire of certitudes.

Now imagine that we didn't have this ability to recognize things within context. Imagine every scenario we encounter was brand new.  We'd have to learn on the fly.  We'd have to take in external stimulus, compare it with only our must unchanging fundamental knowledge and build up a mental representation.  No ability to react in a split second.  No ability to store new knowledge so that next time, we have something to reference.  What would that be like?

It's kind of like the fatal flaw in how we're approaching data recognition in software development.  We merely have the illusion, as users, that the computer knows something we don't.  That it's really able to determine facts for us that we're simply incapable of doing and are thus powerful aids in intelligence.  But software doesn't recognize data.  Not the way we do.  Every time we give software input and tell in to act on that input, it goes through the same motions as every other time.  Even if the input is the same.  Now, this isn't true of all software — artificial intelligence is geared toward learning.  In an effort to simulate real human behaviour, some software can actually recognize certain data, attach meaning to it, and store new information that is applied in the next round.

Should we be taking this type of software more seriously?  That is, should we not view learning software as more of a fundamental necessity for all types of applications?  I think the answer is yes, because until we can effectively build software that can recognize data, the current levels of complexity will soon become recalcitrant.

The Best Help
Imagine using software that could display meaningful error messages.  I know, probably not going to happen in our lifetime, but one can only dream.  What is a meaningful error message?  Well, we're typically used to seeing things like "oops, you forgot the last name field".  This is helpful enough, and probably won't go away until forms vanish from the face of the earth.  But what about errors that tell the user something they have no control over — these usually take the form of "an unknown error occurred" or "the system is a experiencing higher that normal traffic levels...".  You've got to wonder, why even bother.  Why not just say, "this software has bugs, so not your fault".  This is another category with which the user has no control over whether or not the error message gets generated.  So until software just works, we're stuck with these annoyances.

But let's revisit the problem of form entry errors for a moment.  If the user is providing the data, it's much easier to tell them they've done wrong.  They can relate to the message because it's clearly of their own doing.  Most software frameworks have form validation sub-components that supply a primitive form of data recognition.  That is, the field validators can recognize if the supplied data is in fact an email address or if it is in fact a phone number.  These little helpers make the lives of developers writing the software easier and the lives of users supplying input.  The developers know that they can read phone numbers and email addresses from the form.  The users know exactly what they've done wrong in the case of submission failure because the get back meaningful messages.

However, we could take this principle of recognizing what the user has supplied us with to make their lives even easier.  Instead of returning an error message if the email address cannot be recognized. or at least before returning the message, maybe the framework makes an attempt to fix the user's typo.  For example, perhaps the @ character is missing and the first part of the string begins with a human name such as davidcompany.com or david company.com.  The data recognition framework could save the user some typing if all it needs to do is come back with a suggestion — did you mean david@company.com.  Obviously, that's exactly what I meant — good job software.

So is this the best we can do with data recognition in terms of understanding what the user is trying to say?  That is, is the confirmation really necessary?  Do we really need to go back and check if that is in fact what the user meant?  The problem with not checking is that a false positive could result in a much worse situation than if they had simply been given an opportunity to correct things.  And I don't necessarily think that implies that the software is weak or that in stands in the way of the traditional method of input correction.  What it does do is gives the user a sense that the software does know what they're trying to do.  It leaves a feeling of being coached along an activity, not taunted in a guessing game.

I think its a huge win for not only users, and not only developers that create these systems, but more of a collective win for a society that relies on software interactions.  Any good software system must produce fantastic documentation, enabling their users to navigate through the system themselves.  The documentation is simply learning material, some of it will no doubt be memorized, other parts referred to when necessary.  But is thorough text the best learning solution for using a piece of software?  Or is it better to give the users a brief overview — just enough to get them started.  And this is where the data recognition end of thing comes into being for providing users with the ideal help system. The ultimate goal being to recognize what the user is trying to do and to offer advice of how to better achieve their goals.

Effort Required
It's easy to dream about software that recognizes data, correspondingly, making assumptions about what we want to do.  It's a completely different story when it comes to putting these ideas into code.  There simply isn't enough demand for this type of software-assisted user experience.  Well, that might not be entirely true — Apple has made it abundantly clear that we cannot expect anything less than cutting edge user experiences from any of their products.  Even still, the old routine of having to understand, often in some level of detail, what the computer is expecting from us, is somewhat ingrained in our experience.

We can't use the software because it requires training — reading manuals and perhaps some guided practical exercises.  Everyone knows experience is the best teacher — why not streamline that wisdom even further if we have the ability to do so?  Build in some of the mistakes that you'll expect your users to make.

This is part of the challenge — at the intersection of time to market and innovative data recognition solutions.  I have nothing but the utmost confidence that we're able to apply the most sophisticated recognition techniques to almost any software and that we'd see absolutely incredible results.  When push comes to shove, it's hard to justify such efforts.  Which is too bad in my opinion because an investment into data recognition is an investment into customer behaviour.

Data recognition isn't just about users, it isn't just about saving them from typing a few extra characters. More broadly, it's about flexibility in how intent is expressed between actors that exchange information.  Standards are good but only if the two communicating systems speak the same standard.  If we could simply think of more intelligent ways to lower barrier between what the user envisions doing in their head and what that means supplying the keyboard, we'd be well on our way to quality data recognition.