jQuery UI dialogs aid in gathering input from the user. Dialogs jump out from page, usually in response to some user-triggered event such as a button click. When a dialog is displayed, the page layout — that is, the way the page looked before the dialog was displayed — remains unchanged. It's almost like a secondary browser window, harmonized with the rest of the user interface thanks to the theme framework.
The dialog widget isn't a perfect fit for everyone — some might prefer the approach of displaying forms in-line on the page as opposed to having the form jump out at them. But aside from individual user preferences, there are a few implementation issues with displaying data in dialog widgets. Some major API redesign is lined up for the 1.9 version of the dialog widget, aimed at solving some of these imperfections.
One issue I'm interested in seeing worked out is proper disabling of the dialog widget. Subtle cases, where not having the dialog entirely disabled, cause some weird side-effects. And then there are not so subtle breakages where we need to fetch remote data.
Forms and remote data
Forms wouldn't be vary useful in the context of web applications if they didn't somehow interact with the server. For example, submitting a forms often means dispatching a POST HTTP request from the browser to the application server, resulting in a new resource. Sending data to the server is one avenue to interacting with remote data — but the user who submitted the form will need feedback — how else will they know if the action succeeded or not?
The response generated from the form submission should be presented to the user. More often than not, the user will have made an error in one or more fields, so the user interface will need to convey this. The error message — or error messages — typically go beside the errant field.
Dialog widgets that display forms to users have another potential use for remote application data and that is the form itself. Imagine a user clicks a registration button, located on the homepage, which then displays the form in a dialog widget. Now, imagine that this website has several other public informational pages that do not require a login, but nonetheless, we still to display the registration button on these pages. The registration form is the same on all pages.
So where does the dialog widget get the actual markup for this form? The jQuery UI dialog widget uses a div element as it's template — whatever is inside the div is displayed when the dialog is opened. This means that we'll have to insert the form markup on every page where the registration button is present. A solution to avoid duplicate registration forms is to make an Ajax call when the button is clicked. Instead of just opening the dialog, we'll populate the div with remote data first — this way we're only duplicating the URI pointing to the form on each page instead of the form itself.
Three methods in which the form displayed inside a jQuery UI dialog can communicate with the application server — through submitting data, through receiving responses, and through loading the initial form. On their own, the methods aren't difficult to comprehend and implement, but latency and usability are always a concern. An Ajax-based form can take on several states when presented inside a dialog, some of which require the form be disabled.
Disabling form elements
There comes a point, during the communication from the form to the application server, where it'll need to be disabled. Disabling means giving the user a visual cue that the element is temporarily paralyzed. Also, disabled widgets shouldn't respond to user events.
For example, let's say the user has just opened up a registration form inside a dialog widget. Before it can be displayed, we need to retrieve the actual form HTML and insert it into the dialog. In the mean time, while the HTTP request is happening in the background, there isn't anything for the user to see — there is nothing to display in the dialog yet. If we defer displaying the dialog until the form is ready, it appears to the user as though nothing has happened yet — sluggish responses are discouraging.
Display the dialog in a disabled state while the form loads.
What about when the user has actually submitted form data and is awaiting the result? We could hide the dialog entirely while the Ajax response churns. But this is clumsy as there is high probability of having to display the form again for the user to correct errors. It seems the logical solution is to keep the dialog visible, but disabled, just while processing happens. This is a friendly way, a responsive way, to indicate that stuff is happening.
Simple solution to a difficult problem
There are scenarios when using jQuery UI dialog widgets where it makes sense to disable it. Especially when dealing with forms as mentioned above. Sending and receiving remote data while the dialog is open means users can interact with it — unless it's properly disabled. However, while data is being transferred — from the browser to the server — or vice versa — there is a short latency duration.
Ajax-style applications cannot avoid latency during HTTP requests that take place in the background. Or, at least they cannot work under the assumption that the network response time will be faster than user actions. Preventing the user from performing certain actions is easy — it becomes difficult when we take into account the perceived responsiveness of the user interface. There is a delicate balance between ensuring correct behavior while remaining intuitive.
The solution to this problem, as we'll see in the 1.9 release of the jQuery UI dialog widget is to place a div element over top of the dialog, preventing the user from making changes during background processing. The best part about this enhancement, however, is that there is now a simple API for the dialog widget that'll make it disabled. This greatly simplifies many usage scenarios where we're waiting on the application server — we can simply disable the dialog and re-enable it instead of stringing together a boisterous solution.
Thursday, September 29, 2011
Monday, September 26, 2011
Hot-Plugging Data With Python And Libvirt
The CD-ROM drive revolutionized the way we're able to move data around on personal computers. Never mind the internet, the notion of seamlessly transporting information over the wire between two machines was unthinkable fifteen years ago. But besides transferring data back and forth, we've also come to depend on portable storage devices for practical reasons.
Sometimes the network isn't available to us. Or, maybe there is a network, but we simply don't want our data traversing it. We like to carry data around with us — on USB drives.
The portable storage abstraction persists in virtual infrastructures. The same practical limitations we experience with physical machines still affect those that run on a hypervisor — machines aren't going to come pre-loaded with all the data they'll ever need. This is where portable storage — hot-pluggable storage — becomes advantageous.
Data and devices
Plugging data into a virtual machine means setting up a virtual device and attaching it to the domain. With Libvirt, this is easy to do because everything is defined using an XML description. This means that we can create a device on the fly and plug it in — even after the domain is running. Hot-plugging devices like this is important because we can't afford to shut-down the machine, attach a device, and start it up. This incurs too much overhead — not to mention the inflexibility. Imagine you had to reboot your laptop in order for your operating system to recognize a USB drive — you might as well install a new hard drive in the mean time.
Here is an example of how you can pass some arbitrary data to a running virtual machine. There are three phases required here to take a string and transform it into a device the machine can read from:
Let's take a closer look at what we're doing here.
The first function, mkdata(), takes an input value and writes it to a temporary file. But before doing so, it creates a temporary directory for the file. The reason being, we need a directory to create the ISO format for the device.
The second function, mkiso(), takes an input directory and passes it to the mkisofs command. Once the ISO is built, we can remove the temporary directory and return the ISO file location.
The third function, mkdevice(), builds the Libvirt device we're going to attach to the domain. The iso parameter is the ISO file we want to pass to the virtual machine, generated by mkiso(). You'll notice that this is a disk device, as that is what an ISO image is — a disk. The driver element specifies that this disk is in raw format. There are other options available such as qcow, but with this approach, the format is almost always raw. The source element in the device description points to the ISO file we've just generated.
The target element tells the domain what the device label should be. As the Libvirt documentation spells-out, there is never any guarantee that the device label you give it here will be retained by the guest operating system. For example, in our case, we're telling the guest domain to label the new device as sdb — sda is probably taken. However, if sdb is already taken, then we won't know for sure what the device will be called. This is one area that this method is lacking in — ensuring that the device will be named appropriately so it may be referenced later on.
Finally, with these three functions that'll build the device we're ready to attach it to a domain. We do this here by establishing a Libvirt connection and locating the domain we're interested in. Next, we build the device and attach it.
Using the data
If you ran the above example and all went well, you now have a new disk device attached to your domain. This is great — new data has been made available, no need to access a network and no need to reboot. But inside the guest, applications need access to the data to make use of it.
Below is an example of how you could listen for the new device — from within the machine — and read it.
Here, all we're doing is checking, every ten seconds, if the device we just attached exists. If it does, we're then able to mount it and read from the file within the ISO.
Sometimes the network isn't available to us. Or, maybe there is a network, but we simply don't want our data traversing it. We like to carry data around with us — on USB drives.
The portable storage abstraction persists in virtual infrastructures. The same practical limitations we experience with physical machines still affect those that run on a hypervisor — machines aren't going to come pre-loaded with all the data they'll ever need. This is where portable storage — hot-pluggable storage — becomes advantageous.
Data and devices
Plugging data into a virtual machine means setting up a virtual device and attaching it to the domain. With Libvirt, this is easy to do because everything is defined using an XML description. This means that we can create a device on the fly and plug it in — even after the domain is running. Hot-plugging devices like this is important because we can't afford to shut-down the machine, attach a device, and start it up. This incurs too much overhead — not to mention the inflexibility. Imagine you had to reboot your laptop in order for your operating system to recognize a USB drive — you might as well install a new hard drive in the mean time.
Here is an example of how you can pass some arbitrary data to a running virtual machine. There are three phases required here to take a string and transform it into a device the machine can read from:
- Write the string to a file.
- Create an ISO file.
- Build the device XML
The Python code that builds the device an attaches it to a running domain...
import shutil
import os.path
import tempfile
import subprocess
import libvirt
def mkdata(data):
tmpdir = tempfile.mkdtemp()
tmpfile = tempfile.mkstemp(dir=tmpdir)[1]
with open(tmpfile, 'w') as ofile:
ofile.write(data)
return tmpdir
def mkiso(indir):
tmpiso = tempfile.mkstemp(suffix='.iso')[1]
subprocess.call(['mkisofs', '-o', tmpiso, indir])
shutil.rmtree(os.path.abspath(indir))
return tmpiso
def mkdevice(iso):
return """<disk type='file' device='disk'>
<driver name='qemu' type='raw'/>
<source file='%s'/>
<target dev='sdb' bus='usb'/>
</disk>""" % iso
if __name__ == '__main__':
conn = libvirt.open('qemu:///system')
domain = conn.lookupByName('MyVM')
tmpdir = mkdata('Some virtual machine data...')
tmpiso = mkiso(tmpdir)
device = mkdevice(tmpiso)
domain.attachDevice(device)
Let's take a closer look at what we're doing here.
The first function, mkdata(), takes an input value and writes it to a temporary file. But before doing so, it creates a temporary directory for the file. The reason being, we need a directory to create the ISO format for the device.
The second function, mkiso(), takes an input directory and passes it to the mkisofs command. Once the ISO is built, we can remove the temporary directory and return the ISO file location.
The third function, mkdevice(), builds the Libvirt device we're going to attach to the domain. The iso parameter is the ISO file we want to pass to the virtual machine, generated by mkiso(). You'll notice that this is a disk device, as that is what an ISO image is — a disk. The driver element specifies that this disk is in raw format. There are other options available such as qcow, but with this approach, the format is almost always raw. The source element in the device description points to the ISO file we've just generated.
The target element tells the domain what the device label should be. As the Libvirt documentation spells-out, there is never any guarantee that the device label you give it here will be retained by the guest operating system. For example, in our case, we're telling the guest domain to label the new device as sdb — sda is probably taken. However, if sdb is already taken, then we won't know for sure what the device will be called. This is one area that this method is lacking in — ensuring that the device will be named appropriately so it may be referenced later on.
Finally, with these three functions that'll build the device we're ready to attach it to a domain. We do this here by establishing a Libvirt connection and locating the domain we're interested in. Next, we build the device and attach it.
Using the data
If you ran the above example and all went well, you now have a new disk device attached to your domain. This is great — new data has been made available, no need to access a network and no need to reboot. But inside the guest, applications need access to the data to make use of it.
Below is an example of how you could listen for the new device — from within the machine — and read it.
import os, os.path
import subprocess
import time
while True:
if not os.path.exists('/dev/sdb'):
time.sleep(10)
continue
subprocess.call(['mount', '/dev/sdb', '/mnt/sdb'])
for fname in os.listdir('/mnt/sdb'):
with open(os.path.join('/mnt/sdb', fname)) as ifile:
print 'Got some data...'
print ifile.read()
Here, all we're doing is checking, every ten seconds, if the device we just attached exists. If it does, we're then able to mount it and read from the file within the ISO.
Friday, September 23, 2011
Making Data Public
What sort of information should be made public by organizations? The question, phrased like this, means what type of information is displayed on the company's web site? Information for the web has been prepackaged, so to speak, for consumption by human readers. Perhaps the more interesting question is this — what I'm interested in anyway — what type of raw data should be exposed through an API? Who would use such data and for what purpose?
With pre-formatted information, it's difficult to make sense of it in large volumes. Google does this for their search index by crawling monumental assemblages of HTML pages and other web resources. But for those of us who don't have enormous computing centers and the software capable of deciphering these data sets, we need something a little more primitive. Something that'll let our software draw it's own conclusions about public data.
Who wants to expose their data?
The internet changed things for all organizations — large and small. Having a place on the web is no longer a nice-to-have — you simply cannot compete without one. For one thing, consumers have come to expect this — a place where they can gather information on products and or services. Also, the web is a social animal now. Companies need a social presence on the web if they're to engage with their customers.
This is just web technology — read-only web technology. Information on what the business does, how they're a cut above the competition, and so forth. Just the ignition for the social correspondence that follows. I won't bother going into the whole social end of it because it's fairly obvious — it's important.
What isn't so obvious, however — how the specific information organizations publish on their websites is chosen. Obviously, publishing damaging information will come back to haunt the organization commodiously. Hence the reluctancy to publish anything at all. So why take the chance in making more information available to consumers when it's much safer to make less data available?
A competitive edge
Making data public — useful data — will absolutely give your organization a competitive advantage. That of course assumes that you have both interesting data to make available and the know-how to design an API that other software makers can accommodate. If you've got those two things — you're ahead of the game because you're enabling third party software to be developed on your behalf. This software directly impacts how existing and potential customers connect with your organization.
Take Apple's App Store for instance. There is obviously no shortage of applications available for users to install and use. In fact, it is amazingly imbalanced — the number of applications available in the App Store relative to other device maker's software markets.
Developers who make these applications aren't doing it because of the interesting data Apple is exposing through an API — they're doing it because of the iPhone's popularity. There is a much larger potential user base. So how does this relate to making your data available to the general public through an API? Because this is the type of following you want from developers. How useful would the iPhone be without plethora third-party applications? It would still be great device, but it would be missing a lot of things that users want.
Another aspect to the competitive advantage of having third-party software built for you — they'll use your data in ways you haven't thought of. Could Apple really have thought of all the applications available for their devices? Probably, but not in a time frame of just a few years.
Fear of over-exposure
If our companies weren't scared of exposing data items they shouldn't, they probably would have done it years ago, right? I don't think that's necessarily true because we're only still discovering the neat things we can build with other organization's data.
How do you protect yourself from exposing too much information, perhaps leading to a competitive edge for your competition? I'll tell you what won't protect you from it — not making an API for interesting information. The reality is, it's easy to spot weaknesses — every company in the world has at least one. If the competition is smart enough to exploit these weaknesses, they won't need an API to do it.
So listen to your customers — what kind of applications would they find useful? Or, more generally, what information would they find beneficial? Expose that information through an API. Developers will build cool things if the data is valuable. Who knows what new ideas these applications will in turn bring forth.
With pre-formatted information, it's difficult to make sense of it in large volumes. Google does this for their search index by crawling monumental assemblages of HTML pages and other web resources. But for those of us who don't have enormous computing centers and the software capable of deciphering these data sets, we need something a little more primitive. Something that'll let our software draw it's own conclusions about public data.
Who wants to expose their data?
The internet changed things for all organizations — large and small. Having a place on the web is no longer a nice-to-have — you simply cannot compete without one. For one thing, consumers have come to expect this — a place where they can gather information on products and or services. Also, the web is a social animal now. Companies need a social presence on the web if they're to engage with their customers.
This is just web technology — read-only web technology. Information on what the business does, how they're a cut above the competition, and so forth. Just the ignition for the social correspondence that follows. I won't bother going into the whole social end of it because it's fairly obvious — it's important.
What isn't so obvious, however — how the specific information organizations publish on their websites is chosen. Obviously, publishing damaging information will come back to haunt the organization commodiously. Hence the reluctancy to publish anything at all. So why take the chance in making more information available to consumers when it's much safer to make less data available?
A competitive edge
Making data public — useful data — will absolutely give your organization a competitive advantage. That of course assumes that you have both interesting data to make available and the know-how to design an API that other software makers can accommodate. If you've got those two things — you're ahead of the game because you're enabling third party software to be developed on your behalf. This software directly impacts how existing and potential customers connect with your organization.
Take Apple's App Store for instance. There is obviously no shortage of applications available for users to install and use. In fact, it is amazingly imbalanced — the number of applications available in the App Store relative to other device maker's software markets.
Developers who make these applications aren't doing it because of the interesting data Apple is exposing through an API — they're doing it because of the iPhone's popularity. There is a much larger potential user base. So how does this relate to making your data available to the general public through an API? Because this is the type of following you want from developers. How useful would the iPhone be without plethora third-party applications? It would still be great device, but it would be missing a lot of things that users want.
Another aspect to the competitive advantage of having third-party software built for you — they'll use your data in ways you haven't thought of. Could Apple really have thought of all the applications available for their devices? Probably, but not in a time frame of just a few years.
Fear of over-exposure
If our companies weren't scared of exposing data items they shouldn't, they probably would have done it years ago, right? I don't think that's necessarily true because we're only still discovering the neat things we can build with other organization's data.
How do you protect yourself from exposing too much information, perhaps leading to a competitive edge for your competition? I'll tell you what won't protect you from it — not making an API for interesting information. The reality is, it's easy to spot weaknesses — every company in the world has at least one. If the competition is smart enough to exploit these weaknesses, they won't need an API to do it.
So listen to your customers — what kind of applications would they find useful? Or, more generally, what information would they find beneficial? Expose that information through an API. Developers will build cool things if the data is valuable. Who knows what new ideas these applications will in turn bring forth.
Wednesday, September 21, 2011
Idle Ajax Polling
Web applications like to fetch new data resources in the background. Javascript toolkits — in conjunction with Ajax browser technologies — allow the user interface to refresh application data asynchronously. There is no need to reload the page. jQuery has a suite of useful Ajax utilities for fetching new data and parsing it. This frees up the user interface to notify the application server when it needs more data — perhaps on a recurring basis — each request polling for fresh information. But should this sequence use a fire and forget approach?
Seeking new data
Web application user interfaces are different from their more traditional desktop counterparts. With a desktop user interface, it's easy to listen for changes in data — changes the user is interested in. For instance, one pattern might be to have your widgets act as observers on particular pieces of application data. When the data changes, the widget is notified and can thus make the appropriate visual changes.
There is no need for desktop user interface libraries to poll for changes in the underlying application code — the application can notify the user interface. However, with user interfaces that run inside a web browser, data is often stored on the remote application server — so it needs to stay informed. This is easy enough for the user — they simply need to hit the refresh button and voila — up-to-date information.
The emergence of Ajax in Javascript user interfaces revealed some inefficiencies with the refresh button. First of all, hitting refresh is going to retrieve a new copy of the entire web page — this is wasteful as we've already got the user interface — desktop applications aren't going to rebuild the entire screen when changes in data occur. Second, you'll seldom find refresh buttons inside desktop user interfaces — the data finds the user. In other words — web user interfaces should be automatically populated with changes in data.
Since it's difficult to have the application server notify the user interface about these changes — the Javascript needs to poll for data changes in the background. When new data is detected, the interface is updated accordingly. One potential issue with implementing a polling loop is how do we ensure minimal resource usage? After all, each poll needs to travel through the network.
Idle windows
One approach to saving on resources with a polling Javascript user interface is to detect when the browser window is idle. An idle browser window is one that is open with the user interface loaded, but not in focus on the user's desktop. For example, the user might switch tabs or switch to another desktop window entirely. We can attempt to capture these events and modify our polling logic fittingly.
Here is a simplified demo using jQuery that shows how we might use the focus and blur events to start and stop our polling loop respectively.
Resources saved
In the example above, we're polling (not actually polling anything, but you can see where the real Ajax code would go) every three seconds. When the window becomes idle, we stop polling. This signifies that the user is no longer interested in receiving new data from the application server.
By not polling for new data, we're not consuming network bandwidth. We're also not consuming CPU cycles on the client when new data arrives. This is a win for both the client and the web application.
Seeking new data
Web application user interfaces are different from their more traditional desktop counterparts. With a desktop user interface, it's easy to listen for changes in data — changes the user is interested in. For instance, one pattern might be to have your widgets act as observers on particular pieces of application data. When the data changes, the widget is notified and can thus make the appropriate visual changes.
There is no need for desktop user interface libraries to poll for changes in the underlying application code — the application can notify the user interface. However, with user interfaces that run inside a web browser, data is often stored on the remote application server — so it needs to stay informed. This is easy enough for the user — they simply need to hit the refresh button and voila — up-to-date information.
The emergence of Ajax in Javascript user interfaces revealed some inefficiencies with the refresh button. First of all, hitting refresh is going to retrieve a new copy of the entire web page — this is wasteful as we've already got the user interface — desktop applications aren't going to rebuild the entire screen when changes in data occur. Second, you'll seldom find refresh buttons inside desktop user interfaces — the data finds the user. In other words — web user interfaces should be automatically populated with changes in data.
Since it's difficult to have the application server notify the user interface about these changes — the Javascript needs to poll for data changes in the background. When new data is detected, the interface is updated accordingly. One potential issue with implementing a polling loop is how do we ensure minimal resource usage? After all, each poll needs to travel through the network.
Idle windows
One approach to saving on resources with a polling Javascript user interface is to detect when the browser window is idle. An idle browser window is one that is open with the user interface loaded, but not in focus on the user's desktop. For example, the user might switch tabs or switch to another desktop window entirely. We can attempt to capture these events and modify our polling logic fittingly.
Here is a simplified demo using jQuery that shows how we might use the focus and blur events to start and stop our polling loop respectively.
var poller;
$(document).ready(function(){
function poll(){
$('body').append($('<p></p>')
.html('Polled.'));
poller = setTimeout(poll, 3000);
}
$(window).focus(function(event){
$('body').append($('<p></p>')
.html('Active. Starting poll...'));
poll();
});
$(window).blur(function(event){
$('body').append($('<p></p>')
.html('Idle. Stopping poll...'));
clearTimeout(poller);
});
});
Resources saved
In the example above, we're polling (not actually polling anything, but you can see where the real Ajax code would go) every three seconds. When the window becomes idle, we stop polling. This signifies that the user is no longer interested in receiving new data from the application server.
By not polling for new data, we're not consuming network bandwidth. We're also not consuming CPU cycles on the client when new data arrives. This is a win for both the client and the web application.
Tuesday, September 20, 2011
Staying The Course
During the development life cycle of a software product, how does your team veering off into unknown territory? Scope creep — as we're taught early on as software developers — is one obstacle plaguing software projects. This is where even small, minute changes, if allowed to accumulate, yield something something maligned with the original goal.
On the other hand, how does your product evolve if you're not allowed to innovate? Because, often enough, late breaking ideas coalesce during development — not after it's finished, not during requirements gathering — but while you're coding. Taking these great ideas that pop into mind and pushing them out until a later date — just so you can stick with your plan — kills their momentum.
So it turns out that staying the course is a difficult thing to do. You need a concise goal and commitment to fulfill it — by keeping out unnecessary features and making sure the thing ships on time. Is it possible to sneak stuff in while honoring your stipulations to the project?
No time wasted
Time is of the essence for software development — do more with less. Otherwise, the bigger guys, your competition, will hit the mark. Freedom to muck around with experimental concepts isn't exactly palpable come crunch time — code needs to be rock solid, ready to pass any QA tests and make it into a production environment.
The question is — how do you make resilient code while under time pressure? That is a challenge and why writing code professionally is difficult — you have no such freedoms. You can't devise a selection of alternative solutions and evaluate the best one. There is no time. You have to go with what works initially and, if luck finds you, you'll get a chance to refactor and improve your code later on. That is a big if, of course. How often do you put TODOs in your comments that never go away?
So if you can understand why time is so important during the fragile embryonic development stage of a project, perhaps you can formulate better ways to do more with it. Better ways to improve your coding standards.
One way to look at it is this — it isn't so much a problem with time as much as it is with functionality — the behavior of your software. Because what your software does dictates how much time you'll need to implement it. Part of being agile is doing small development-release iterations — short time frames. So this means that the scheduled features need to take into account the timeline, and not the other way around. I think this is a major breakthrough in how we do software — understanding that yes, people do expect code on a regular basis and yes, there is a fixed number of accomplishments teams can make in that interval.
Time is of the essence, not the software. Considering the amount of time you have to do something — before it's considered production-ready and hits the shelves — is perhaps the first and foremost determinant of any project's success. If the interval means only small, minute changes can be done, then the reality is, the schedule needs to change, not the way we write code.
What does your software do?
You'd be surprised — I find I do this myself — how often I hear developers talk about what their software will do when asked what it does. I find it interesting that we're so fixated on the future — how do we make sure our software is future-proof? The problem with that sentiment is that it doesn't support the notion of problem-solving aspired software development.
We all know that mission statements can be loathsome at times — but they can be a powerful tool in staying focused on solving the problem at hand. All software solves a particular problem — if the mission of the software is to solve the problem, or to at lease appease it to some degree, then you should be able to state how it'll do that. What you need is a consolidated, fundamental kernel that your software derives from — the problem and what your software does about it.
This makes describing what your software does much easier. With a declarative foundation of what your software does, you can reference it throughout the entire lifespan of the project. Having such an immutable artifact means that you can put it to good use when it comes time to evaluate what features are going to make it in and which don't. Consider whether the proposed feature will have a positive impact on your mission statement before spending any real time on it. Having said that, we've now got two primordial tools for staying the course — the mission statement and the knowledge that time is of the essence.
Some things add up
How are we to treat these axiomatic rules — or restrictions — of software development? The two seem very prohibitive to making any sort of progress whatsoever. On the one hand, we've got time working against us — pushing forward, never slowing, always diminishing what resources we do have. On the other, we've got a bombardment of requests and other issues to figure out — all while making something that solves a particular problem.
We need to innovate around these constraints. That is, instead of trying to beat the competition by jumping ahead and pretending that time isn't of the essence or that building new features that don't support the mission statement, we should stay the course. Innovation means recognizing these constraints and beating the odds.
On the other hand, how does your product evolve if you're not allowed to innovate? Because, often enough, late breaking ideas coalesce during development — not after it's finished, not during requirements gathering — but while you're coding. Taking these great ideas that pop into mind and pushing them out until a later date — just so you can stick with your plan — kills their momentum.
So it turns out that staying the course is a difficult thing to do. You need a concise goal and commitment to fulfill it — by keeping out unnecessary features and making sure the thing ships on time. Is it possible to sneak stuff in while honoring your stipulations to the project?
No time wasted
Time is of the essence for software development — do more with less. Otherwise, the bigger guys, your competition, will hit the mark. Freedom to muck around with experimental concepts isn't exactly palpable come crunch time — code needs to be rock solid, ready to pass any QA tests and make it into a production environment.
The question is — how do you make resilient code while under time pressure? That is a challenge and why writing code professionally is difficult — you have no such freedoms. You can't devise a selection of alternative solutions and evaluate the best one. There is no time. You have to go with what works initially and, if luck finds you, you'll get a chance to refactor and improve your code later on. That is a big if, of course. How often do you put TODOs in your comments that never go away?
So if you can understand why time is so important during the fragile embryonic development stage of a project, perhaps you can formulate better ways to do more with it. Better ways to improve your coding standards.
One way to look at it is this — it isn't so much a problem with time as much as it is with functionality — the behavior of your software. Because what your software does dictates how much time you'll need to implement it. Part of being agile is doing small development-release iterations — short time frames. So this means that the scheduled features need to take into account the timeline, and not the other way around. I think this is a major breakthrough in how we do software — understanding that yes, people do expect code on a regular basis and yes, there is a fixed number of accomplishments teams can make in that interval.
Time is of the essence, not the software. Considering the amount of time you have to do something — before it's considered production-ready and hits the shelves — is perhaps the first and foremost determinant of any project's success. If the interval means only small, minute changes can be done, then the reality is, the schedule needs to change, not the way we write code.
What does your software do?
You'd be surprised — I find I do this myself — how often I hear developers talk about what their software will do when asked what it does. I find it interesting that we're so fixated on the future — how do we make sure our software is future-proof? The problem with that sentiment is that it doesn't support the notion of problem-solving aspired software development.
We all know that mission statements can be loathsome at times — but they can be a powerful tool in staying focused on solving the problem at hand. All software solves a particular problem — if the mission of the software is to solve the problem, or to at lease appease it to some degree, then you should be able to state how it'll do that. What you need is a consolidated, fundamental kernel that your software derives from — the problem and what your software does about it.
This makes describing what your software does much easier. With a declarative foundation of what your software does, you can reference it throughout the entire lifespan of the project. Having such an immutable artifact means that you can put it to good use when it comes time to evaluate what features are going to make it in and which don't. Consider whether the proposed feature will have a positive impact on your mission statement before spending any real time on it. Having said that, we've now got two primordial tools for staying the course — the mission statement and the knowledge that time is of the essence.
Some things add up
How are we to treat these axiomatic rules — or restrictions — of software development? The two seem very prohibitive to making any sort of progress whatsoever. On the one hand, we've got time working against us — pushing forward, never slowing, always diminishing what resources we do have. On the other, we've got a bombardment of requests and other issues to figure out — all while making something that solves a particular problem.
We need to innovate around these constraints. That is, instead of trying to beat the competition by jumping ahead and pretending that time isn't of the essence or that building new features that don't support the mission statement, we should stay the course. Innovation means recognizing these constraints and beating the odds.
Friday, September 16, 2011
jQuery UI Grid And OData
The jQuery UI grid widget has yet to see the light of day. Even though it's still a work in progress, things are looking very positive. Earlier on in the jQuery UI grid development, I wrote about the zero-feature grid — one in which the grid data is based on the traditional HTML table. The difference, of course, is that jQuery UI widgets embellish the markup and add CSS classes from the theme framework.
But any grid widget will have to be slightly more effective at retrieving data — more efficient. The zero feature grid is meant as a starting point from where we can transition our existing HTML table structures into grid widget. Once the grid widget is ready for a future release, we'll be in for a nice surprise — a standardized method of passing data to our grids.
JSON is almost a standard
For a grid widget to display our data, it needs to retrieve it from the application server somehow. The traditional, legacy approach is to embed the data inside the presentation structure itself — as is typical of HTML tables. There are a couple obstacles to overcome, however. For one, you can't use any APIs you've built for your application — unless they're returning data in HTML table format — unlikely. So, what is an alternative? Our widget is probably going to require some other form of markup — one better suited for transferring data — not data lodged inside of presentation markup.
That sounds easy enough — all we have to do is implement our API URIs — each returning a JSON response. So, in the case of a grid widget, it simply makes an API request for a list of JSON objects to display in the grid. With this approach, our user interface can share data access patterns — the API — with other third-party applications. Also, we're no longer obligated to return data that conforms to specific user interface idiosyncrasies. At least in theory, that's what we've achieved with the JSON approach.
In practice, however, you can't escape at least some level of coupling between the user interface and the API supplying it with data. The user interface has to know what to expect from the API — what format is being returned, what the object representations look like. Or, perhaps you've already designed a widget that you want to use for a new API. In this case, your user interface has a direct impact on the API design. So you might be making prodigal compromises in both the user interface and the API.
The problem underscored when building custom APIs that support reuse with widgets is a perplexing task. Having at least a small set of common functionality is possible with the help of JSON — but it isn't exactly a standard — it's more of an informal notation. Powerful as JSON is as a lightweight tactic for transferring data over the wire — it doesn't help our standards within applications.
OData is a standard
The OData — Open Data Protocol — aims to solve some of the problems inherent with trying to use the same data set with different widgets or to create new APIs for existing widgets. Aside from the JSON format itself, one problem with the ad hoc RESTful JSON APIs we've seen is that their resource URI's aren't consistent.
Another issue, one that more closely relates to the run time of the client code itself, is that of sorting and filtering data. Sometimes, with large data sets, it is either impractical or impossible to do this locally on the client hardware. So the API must offer the client a means to specify what filtering must take place before the actual data is returned. Again, this is difficult to be consistent with simply because we've now got to reach a consensus on how these arguments are passed to the listing resource. There is more than one way to do these things, and I'm not sure there is any merit in contemplating the correct way unless it is stated outright in the standard.
Specifying data transformations consistently is a key issue that OData attempts to solve for applications that implement it. We have a standardized, methodical approach to asking for the specific data we need. With that in mind, we can go about designing our widgets around the data they're expecting to see because we have a general idea of how to ask for it.
Almost like streaming media
Based on the examples I've seen so far that highlight the jQuery UI grid widget — still under heavy development — it appears as though the grid has the potential to behave like a media player. Instead of binary video data being sent to the Flash or HTML 5 video element, the widget can display semantic application data. The amount of effort required by the developer to make this a reality is negligable — especially if the application is already utilizing OData.
Now here is the really fun part. Also like media elements, you can point your jQuery UI grid data source to a third party service that implements OData. The example OData jQuery UI grid retrieves a list of titles from the Netflix API.
We'll still have to wait and see what the finished product looks like some solid design decisions are being fulfilled. The grid, use in an OData source as it's input stream, is like a flexible "data player".
But any grid widget will have to be slightly more effective at retrieving data — more efficient. The zero feature grid is meant as a starting point from where we can transition our existing HTML table structures into grid widget. Once the grid widget is ready for a future release, we'll be in for a nice surprise — a standardized method of passing data to our grids.
JSON is almost a standard
For a grid widget to display our data, it needs to retrieve it from the application server somehow. The traditional, legacy approach is to embed the data inside the presentation structure itself — as is typical of HTML tables. There are a couple obstacles to overcome, however. For one, you can't use any APIs you've built for your application — unless they're returning data in HTML table format — unlikely. So, what is an alternative? Our widget is probably going to require some other form of markup — one better suited for transferring data — not data lodged inside of presentation markup.
That sounds easy enough — all we have to do is implement our API URIs — each returning a JSON response. So, in the case of a grid widget, it simply makes an API request for a list of JSON objects to display in the grid. With this approach, our user interface can share data access patterns — the API — with other third-party applications. Also, we're no longer obligated to return data that conforms to specific user interface idiosyncrasies. At least in theory, that's what we've achieved with the JSON approach.
In practice, however, you can't escape at least some level of coupling between the user interface and the API supplying it with data. The user interface has to know what to expect from the API — what format is being returned, what the object representations look like. Or, perhaps you've already designed a widget that you want to use for a new API. In this case, your user interface has a direct impact on the API design. So you might be making prodigal compromises in both the user interface and the API.
The problem underscored when building custom APIs that support reuse with widgets is a perplexing task. Having at least a small set of common functionality is possible with the help of JSON — but it isn't exactly a standard — it's more of an informal notation. Powerful as JSON is as a lightweight tactic for transferring data over the wire — it doesn't help our standards within applications.
OData is a standard
The OData — Open Data Protocol — aims to solve some of the problems inherent with trying to use the same data set with different widgets or to create new APIs for existing widgets. Aside from the JSON format itself, one problem with the ad hoc RESTful JSON APIs we've seen is that their resource URI's aren't consistent.
Another issue, one that more closely relates to the run time of the client code itself, is that of sorting and filtering data. Sometimes, with large data sets, it is either impractical or impossible to do this locally on the client hardware. So the API must offer the client a means to specify what filtering must take place before the actual data is returned. Again, this is difficult to be consistent with simply because we've now got to reach a consensus on how these arguments are passed to the listing resource. There is more than one way to do these things, and I'm not sure there is any merit in contemplating the correct way unless it is stated outright in the standard.
Specifying data transformations consistently is a key issue that OData attempts to solve for applications that implement it. We have a standardized, methodical approach to asking for the specific data we need. With that in mind, we can go about designing our widgets around the data they're expecting to see because we have a general idea of how to ask for it.
Almost like streaming media
Based on the examples I've seen so far that highlight the jQuery UI grid widget — still under heavy development — it appears as though the grid has the potential to behave like a media player. Instead of binary video data being sent to the Flash or HTML 5 video element, the widget can display semantic application data. The amount of effort required by the developer to make this a reality is negligable — especially if the application is already utilizing OData.
Now here is the really fun part. Also like media elements, you can point your jQuery UI grid data source to a third party service that implements OData. The example OData jQuery UI grid retrieves a list of titles from the Netflix API.
We'll still have to wait and see what the finished product looks like some solid design decisions are being fulfilled. The grid, use in an OData source as it's input stream, is like a flexible "data player".
Thursday, September 15, 2011
Libvirt And The Virtual Standard
Libvirt is more than just a virtualization library — it strives for standardization among virtual resources. This matters because hypervisors abound, they all have different capabilities. The Libvirt library assimilates an interface for communicating with different hypervisor technology and treating them as one in the same. But there is more to the Libvirt API than just functions that create and manipulate virtual machines.
More than machines
There is certainly more to operating a virtual infrastructure than provisionally instantiating and terminating virtual machines. There are networks, there is storage, and there are the physical hosts themselves who carry out these operations. Any virtualization library hoping to elucidate these things will need to differentiate between them — to create abstractions for them.
Considering the number of hypervisors that Libvirt actually supports, this is a challenging feat — the goal is for the developer using the library to have a seamless integration between the divergent hypervisors.
These abstractions are the virtual entities that comprise virtual infrastructures. To be interoperable, they need to behave the same. That is, their external interfaces must not differ per hypervisor connection. If it were just the virtual machine control we're concerned with — starting, stopping, destroying, snap-shots — this would be no problem. But the fact of the matter is that there are dozens of virtual entity types that need to be acknowledged.
In addition to other virtual entities such as networking and storage, the machine entities themselves have internal parts. Machines are composites made up of several smaller components — CPUs, disk devices, memory. These all fall outside of the core virtualization idea of emulating CPU instructions. Effectively managing a large-scale, or even a mid-scale virtual environments, requires abstraction at a higher level.
Virtual documents
Inside code that uses Libvirt, inside the Python binding at least, these virtual entities are represented as traditional objects. Just like a user object or a file object, virtual entities have methods and attributes — used to query the state of the object or to alter it in some fashion. What is unique about how Libvirt deals with it's virtual entities is that they're described in an XML format. Any given virtual entity can be reduced to an XML description. A document.
Whats interesting to me about this approach is that XML has an inherent ability to be decomposed and rearranged. Any programming language can parse and generate XML data — so with any virtual entity XML from Libvirt, we're able to take it's XML description and splice it up into several smaller documents should we choose to do so.
For example, the XML schema for domains — virtual machines — in Libvirt can be somewhat lengthy. The XML description needs to tell Libvirt about everything the machine needs to operate, including all devices, CPU tuning, network connections, etc. So of course it's going to have some heft to it. Our software that uses Libvirt can take a given XML description for a domain an find the interesting sub-elements it needs — it can drill down and organize the domain data in it's own way.
A side-effect to using XML in this way is that it gives the various components of our virtual infrastructure the freedom to devise their own abstractions for virtual entities. Let's say you want a memory abstraction — one for domains that you can use to attach additional behavior. The memory abstraction is then constructed based on the parsed domain XML. Additionally, this abstraction could play a role in constructing XML descriptions for domains.
Another corollary to XML documents is that they're documents — they've an inherent ability to be treated as shared resources that can be passed around in a distributed environment.
More than one host
Another, perhaps less obvious, reason for having XML documents describe the virtual entities in our infrastructure is that there are going to be multiple hosts. The host is where the hypervisor manages virtual machines, so you're going to need more than one. Libvirt really shines here because our hyperviser environment may be heterogeneous — many different hypervisors each with their own physical hardware.
Now imagine that we've got our own tailor made software for controlling various things — the management of the virtual infrastructure. This means that we'll need to pass around virtual XML documents to various hosts that control the entity.
For example, let's say we want to define a new domain. Our software builds the XML document that will tell Libvirt how to make it. Our first attempt to create and start the domain on host A fails. So we can try it again on another host in our infrastructure. In theory, we shouldn't care what hypervisor is running on host B for our second attempt — the same XML document that defines the domain will do. This is a key benefit of having a standardized XML schema for virtual entities — there is one schema for many hypervisors.
Outside of the XML standardization, Libvirt offers another type of virtualization standard — connecting to multiple hosts. It is one thing to write some agent code that will use Libvirt to control our virtual infrastructure. This code will need to live on each host where the hypervisor runs. But, alas, we can use Libvirt to establish remote connections to the hypervisor in a heterogeneous way. What this part of the virtual standard libvirt implements means is that we can put more focus on our controlling code — we can worry more about making stuff that best promotes our infrastructure. The physical hosts we're using don't need our application running on them — only Libvirt and the hypervisor itself.
The absent stuff
The Libvirt library fills a large gap between disparate hypervisor technologies. Perhaps most important, Libvirt unifies the virtual entities common in any infrastructure and abstracts them. This is how we're able to use multiple hosts to deploy virtual machines without having to worry about the hypervisor installed on each. Another innovation in the virtualization standard that we're sorely missing in this field is that of the XML document — used to describe virtual entities. The concept of an XML document isn't new to most code and can be easily and quickly adapted for any software.
But despite these achievements, Libvirt isn't exactly a standard — although, there isn't anything else that better unifies virtualization technology. There is still some betterment that needs to take place in order to better facilitate our infrastructures. For example, we know little about the capabilities of the hypervisor's host — this XML schema still hasn't solidified. Another hurdle in the virtual standard is that despite having abstract entities, not every hypervisor is going to support identical functionality that Libvirt offers. Our code that uses Libvirt can sort these errors out, but one must ask, can there really be a standard where not all hypervisors agree on at least a minimal set of common features?
More than machines
There is certainly more to operating a virtual infrastructure than provisionally instantiating and terminating virtual machines. There are networks, there is storage, and there are the physical hosts themselves who carry out these operations. Any virtualization library hoping to elucidate these things will need to differentiate between them — to create abstractions for them.
Considering the number of hypervisors that Libvirt actually supports, this is a challenging feat — the goal is for the developer using the library to have a seamless integration between the divergent hypervisors.
These abstractions are the virtual entities that comprise virtual infrastructures. To be interoperable, they need to behave the same. That is, their external interfaces must not differ per hypervisor connection. If it were just the virtual machine control we're concerned with — starting, stopping, destroying, snap-shots — this would be no problem. But the fact of the matter is that there are dozens of virtual entity types that need to be acknowledged.
In addition to other virtual entities such as networking and storage, the machine entities themselves have internal parts. Machines are composites made up of several smaller components — CPUs, disk devices, memory. These all fall outside of the core virtualization idea of emulating CPU instructions. Effectively managing a large-scale, or even a mid-scale virtual environments, requires abstraction at a higher level.
Virtual documents
Inside code that uses Libvirt, inside the Python binding at least, these virtual entities are represented as traditional objects. Just like a user object or a file object, virtual entities have methods and attributes — used to query the state of the object or to alter it in some fashion. What is unique about how Libvirt deals with it's virtual entities is that they're described in an XML format. Any given virtual entity can be reduced to an XML description. A document.
Whats interesting to me about this approach is that XML has an inherent ability to be decomposed and rearranged. Any programming language can parse and generate XML data — so with any virtual entity XML from Libvirt, we're able to take it's XML description and splice it up into several smaller documents should we choose to do so.
For example, the XML schema for domains — virtual machines — in Libvirt can be somewhat lengthy. The XML description needs to tell Libvirt about everything the machine needs to operate, including all devices, CPU tuning, network connections, etc. So of course it's going to have some heft to it. Our software that uses Libvirt can take a given XML description for a domain an find the interesting sub-elements it needs — it can drill down and organize the domain data in it's own way.
A side-effect to using XML in this way is that it gives the various components of our virtual infrastructure the freedom to devise their own abstractions for virtual entities. Let's say you want a memory abstraction — one for domains that you can use to attach additional behavior. The memory abstraction is then constructed based on the parsed domain XML. Additionally, this abstraction could play a role in constructing XML descriptions for domains.
Another corollary to XML documents is that they're documents — they've an inherent ability to be treated as shared resources that can be passed around in a distributed environment.
More than one host
Another, perhaps less obvious, reason for having XML documents describe the virtual entities in our infrastructure is that there are going to be multiple hosts. The host is where the hypervisor manages virtual machines, so you're going to need more than one. Libvirt really shines here because our hyperviser environment may be heterogeneous — many different hypervisors each with their own physical hardware.
Now imagine that we've got our own tailor made software for controlling various things — the management of the virtual infrastructure. This means that we'll need to pass around virtual XML documents to various hosts that control the entity.
For example, let's say we want to define a new domain. Our software builds the XML document that will tell Libvirt how to make it. Our first attempt to create and start the domain on host A fails. So we can try it again on another host in our infrastructure. In theory, we shouldn't care what hypervisor is running on host B for our second attempt — the same XML document that defines the domain will do. This is a key benefit of having a standardized XML schema for virtual entities — there is one schema for many hypervisors.
Outside of the XML standardization, Libvirt offers another type of virtualization standard — connecting to multiple hosts. It is one thing to write some agent code that will use Libvirt to control our virtual infrastructure. This code will need to live on each host where the hypervisor runs. But, alas, we can use Libvirt to establish remote connections to the hypervisor in a heterogeneous way. What this part of the virtual standard libvirt implements means is that we can put more focus on our controlling code — we can worry more about making stuff that best promotes our infrastructure. The physical hosts we're using don't need our application running on them — only Libvirt and the hypervisor itself.
The absent stuff
The Libvirt library fills a large gap between disparate hypervisor technologies. Perhaps most important, Libvirt unifies the virtual entities common in any infrastructure and abstracts them. This is how we're able to use multiple hosts to deploy virtual machines without having to worry about the hypervisor installed on each. Another innovation in the virtualization standard that we're sorely missing in this field is that of the XML document — used to describe virtual entities. The concept of an XML document isn't new to most code and can be easily and quickly adapted for any software.
But despite these achievements, Libvirt isn't exactly a standard — although, there isn't anything else that better unifies virtualization technology. There is still some betterment that needs to take place in order to better facilitate our infrastructures. For example, we know little about the capabilities of the hypervisor's host — this XML schema still hasn't solidified. Another hurdle in the virtual standard is that despite having abstract entities, not every hypervisor is going to support identical functionality that Libvirt offers. Our code that uses Libvirt can sort these errors out, but one must ask, can there really be a standard where not all hypervisors agree on at least a minimal set of common features?
Tuesday, September 13, 2011
What URIs Say About Resources
The web today is made up of boundless resources — each identified by their URI. I favor the term URI over URL because it denotes identity. So what information can we gather from the URI alone? Are we better of calling it a URL since the mail purpose is to do a lookup? I don't think so because the fact that URIs are used to look something up is implied knowledge — it's the identity of the resource we want to learn about. But, can we attain this type of information from the URI alone or is it a meaningless question? URI's should be designed to advocate foreknowledge of what the resource is.
Uniqueness
URIs are unique. That is, there is a one-to-one mapping between a URI and the resource it points to. There are, of course, exceptions to this rule. For example, you might have a radio station web application that displays the currently playing artist. During the artist's air time, they might have a artist/current URI that points to the artist's detail page. Alternatively, there might be a single canonical URI associated with the artist's page — artist/123 for instance.
So in the case of the former — where the artist can have two URIs pointing to their page — there is no one-to-one mapping of URI to resource. There might even be more than two URIs pointing to the artist's page — charts/top, for instance. But these URIs are unique in that they're referring to one resource. The underlying resource might change — the artist/current URI stays the same but the resource it points to will change frequently.
The artist/current URI is an example of a virtual resource — to the external agent, this appears to be where the resource lives. But this isn't where the resource lives — it isn't it's canonical URI. The URI artist/123 is static and probably will never change. The virtual URI points to the canonical URI.
To better illustrate this concept, let's talk in hockey terms. Imagine the center for the home team. He is number 15. So his canonical resource URI looks like home/15. Now imagine that you want a URI for the home team player currently in possession of the puck. Our star center has the puck — so we can represent this as a virtual URI — puck/control. There isn't anything special about this URI — it just contains some logic that points to the home/15 URI.
Meaning
So it turns out that URIs carry some important information after all. And this is what I'm trying to figure out. Exactly how much information is of value to the reader of the URI? In theory, every URI on the web could be some arbitrary string — CD4F2ACF4, for example. It wouldn't matter because information is properly linked to other information. The readers don't care what the URI is — they only care about the anchor text.
I think this might have some degree of truth behind it but the reality is that people do care about the URI and what it looks like. I know I do. In fact, before clicking on links, I find myself hovering over them to see where they go — trying to examine the URI to guess it's worth before I go there. Mind you, I take a very active interest in URI design — so I doubt every single user will scrutinize — or even care for that matter — what a URI looks like.
But it turns out that even the most arbitrary URIs make subtle attempts to attach meaning. Consider our earlier URI — artist/123. What do we know about this page before visiting it? Even if you're a lay user — you're probably able to guess that it has something to do with an artist. We achieve two things with this URI — the vocabulary and the multiplicity.
The vocabulary establishes the kind of thing users can expect to see should they choose to follow the link — in this case, an artist. The multiplicity is established in two ways. First, we're explicitly choosing the term artist, not artists. Second, the reader can see the trailing identifier — 123.
So the most meaningful piece of information in this URI is artist. The arbitrary part, arbitrary from the reader's perspective, is both meaningless and important at the same time. The arbitrary identifier assigned to the resource is an important part of the URI — it's what makes it canonical. The number itself has no meaning to the user but it has utility in sharing that URI with others.
Evolution
It turns out that URI design has evolved quite a lot since the emergence of the web. We've seen a lot of resources — immeasurable resources — created over the years. This directly impacts our ability to create meaningful URIs for users. If it were simply a matter of incrementing the resource count once a new resource is created, we'd be all set. Unfortunately, that isn't true at all. There are new types of resources that need to be created as applications and organizations evolve. These new resource types are going to form an ever more complex mesh of relationships — links to other resources both new and old.
These new resource types — once invented to help solve the technological problems of the day — will also need virtual resources. The virtual resources are the logic of the web — they're not real data, just pointers to other canonical resources that store the real information that external agents update and use.
Keeping URLs meaningful for users is important as available information continues to expand. If we succumb to churning out completely arbitrary URIs, we're taking a step backward. Likewise, the URI itself is real data that needs to be shared and passed around — so we must be careful to add meaning, but not too much.
Uniqueness
URIs are unique. That is, there is a one-to-one mapping between a URI and the resource it points to. There are, of course, exceptions to this rule. For example, you might have a radio station web application that displays the currently playing artist. During the artist's air time, they might have a artist/current URI that points to the artist's detail page. Alternatively, there might be a single canonical URI associated with the artist's page — artist/123 for instance.
So in the case of the former — where the artist can have two URIs pointing to their page — there is no one-to-one mapping of URI to resource. There might even be more than two URIs pointing to the artist's page — charts/top, for instance. But these URIs are unique in that they're referring to one resource. The underlying resource might change — the artist/current URI stays the same but the resource it points to will change frequently.
The artist/current URI is an example of a virtual resource — to the external agent, this appears to be where the resource lives. But this isn't where the resource lives — it isn't it's canonical URI. The URI artist/123 is static and probably will never change. The virtual URI points to the canonical URI.
To better illustrate this concept, let's talk in hockey terms. Imagine the center for the home team. He is number 15. So his canonical resource URI looks like home/15. Now imagine that you want a URI for the home team player currently in possession of the puck. Our star center has the puck — so we can represent this as a virtual URI — puck/control. There isn't anything special about this URI — it just contains some logic that points to the home/15 URI.
Meaning
So it turns out that URIs carry some important information after all. And this is what I'm trying to figure out. Exactly how much information is of value to the reader of the URI? In theory, every URI on the web could be some arbitrary string — CD4F2ACF4, for example. It wouldn't matter because information is properly linked to other information. The readers don't care what the URI is — they only care about the anchor text.
I think this might have some degree of truth behind it but the reality is that people do care about the URI and what it looks like. I know I do. In fact, before clicking on links, I find myself hovering over them to see where they go — trying to examine the URI to guess it's worth before I go there. Mind you, I take a very active interest in URI design — so I doubt every single user will scrutinize — or even care for that matter — what a URI looks like.
But it turns out that even the most arbitrary URIs make subtle attempts to attach meaning. Consider our earlier URI — artist/123. What do we know about this page before visiting it? Even if you're a lay user — you're probably able to guess that it has something to do with an artist. We achieve two things with this URI — the vocabulary and the multiplicity.
The vocabulary establishes the kind of thing users can expect to see should they choose to follow the link — in this case, an artist. The multiplicity is established in two ways. First, we're explicitly choosing the term artist, not artists. Second, the reader can see the trailing identifier — 123.
So the most meaningful piece of information in this URI is artist. The arbitrary part, arbitrary from the reader's perspective, is both meaningless and important at the same time. The arbitrary identifier assigned to the resource is an important part of the URI — it's what makes it canonical. The number itself has no meaning to the user but it has utility in sharing that URI with others.
Evolution
It turns out that URI design has evolved quite a lot since the emergence of the web. We've seen a lot of resources — immeasurable resources — created over the years. This directly impacts our ability to create meaningful URIs for users. If it were simply a matter of incrementing the resource count once a new resource is created, we'd be all set. Unfortunately, that isn't true at all. There are new types of resources that need to be created as applications and organizations evolve. These new resource types are going to form an ever more complex mesh of relationships — links to other resources both new and old.
These new resource types — once invented to help solve the technological problems of the day — will also need virtual resources. The virtual resources are the logic of the web — they're not real data, just pointers to other canonical resources that store the real information that external agents update and use.
Keeping URLs meaningful for users is important as available information continues to expand. If we succumb to churning out completely arbitrary URIs, we're taking a step backward. Likewise, the URI itself is real data that needs to be shared and passed around — so we must be careful to add meaning, but not too much.
Labels:
design
,
information
,
resource
,
uri
Monday, September 12, 2011
Gnome 3 First Impressions
Last week, I decided to pull the trigger and install Gnome 3 on my Ubuntu laptop. I made an attempt to embrace Unity when it was first released — that didn't last long. Aside from a few configuration disturbances, my first impression is that Gnome 3 rocks.
Time for change
So why change at all? I've been using a Gnome 2 desktop environment for years. It looks good, it works as you'd expect a desktop to work, and it's open source — all good enough reasons to stick with Gnome 2.
However, things change. Sometimes a radical departure from the norm is necessary to spearhead innovations. This is true of any discipline — not restricted to desktop environments, nor information technology in general. Every field occasionally partakes in a drastic shakeup. Otherwise, be become too complacent and nothing ever happens.
Ubuntu recognized the potential user experience improvements — improvements in how users engage the operating system. Not minor tweaks, not smoothing out rough edges, but an exorbitant change in the fundamental workflow. Ubuntu introduced Unity as an enhanced desktop experience. Not a new desktop environment, but a guise for the traditional Gnome 2 environment.
I was intrigued by this idea and was looking forward to what Unity would look like and how it would change my daily routine — hopefully for the better.
The failed experiment
Once the shock wore off — the shock of my desktop being transformed into something completely foreign — I started to familiarize myself with Unity. At first, it seemed like it had potential. While I was still acquainting myself with the new Ubuntu, I started to listening to some of the frustrations voiced by the Ubuntu user community. The unanimous question about Unity seemed to be how do I turn it off?
Hearing almost nothing good about this new environment, aimed at making life easier for users, I found it difficult to ignore. Granted, many complaints about Unity I was taking in were a little nit-picky and couldn't relate to. So I carried on, determined to change how my desktop worked for the better.
I must say, I admire the ambition behind the project — Unity definitely had potential but there were just too many minor issues. Aside from the bugs, Unity just didn't mesh well — didn't feel like part of the desktop. So more than just subtle bugs — Unity was a failed experiment in desktop experience. Once I switched back to Gnome 2, in it's traditional form, I felt home again. It was like I had gone on a vacation and had everything go wrong. Switching to Gnome 3 felt like a permanent vacation.
Almost, getting there...
I used the traditional Gnome 2 environment happily for about four months after turning Unity off. Then my restlessness desire for change kicked in again. I knew Gnome 3 had been released, why couldn't I try it out? It seemed like the logical evolution for my desktop environment. Luckily, I found a guide that helped me get Gnome 3 going in about an hour.
This was last week, so I'm still a new citizen here. Gnome 3 has a semblance to Unity only it doesn't feel like an addition to the desktop. The enhancements in Gnome 3 truly feel like part of the whole experience.
One common goal both Unity and Gnome 3 have is to better utilize the screen space. This means that you don't have a static task bar that shows the user all their currently open windows. The idea instead is to only show the currently running applications when it really matters. Like when I want to switch windows. In Gnome 3, I just click activities in the top left of my screen. This gives me a nice preview of what I have open at the moment.
Let's say I want to launch a new application. I can click activities again to see my favorites pane where I've added my commonly used applications. However, there is also the application menu, beside my currently open windows. I can click here to browse applications by category. This is handy if I don't know off hand the name of the application I want to run. Alternatively, when you click activities, you can just start typing the name of the application — this will bring up matches for you automatically. I've found this to be an incredibly powerful feature. I hardly ever use the favorites pane in favor of just typing a few characters and hitting enter to launch something.
In this era of streamlined desktop environments — one where space is of virtue, it's sometimes difficult to find your way around. I don't think these radical changes brought on by Unity and Gnome 3 are workflow defects, just something new and different. We've been using the standardized desktop layout for a really long time. So even if this is the sub-optimal approach to desktop computing, it's what we're used to. We've grown attached to the way we do things in our local environments, I know I have. Change is difficult, but Gnome 3 makes it a little less painful. It isn't perfect, but I truly believe it is a step in the right direction.
Time for change
So why change at all? I've been using a Gnome 2 desktop environment for years. It looks good, it works as you'd expect a desktop to work, and it's open source — all good enough reasons to stick with Gnome 2.
However, things change. Sometimes a radical departure from the norm is necessary to spearhead innovations. This is true of any discipline — not restricted to desktop environments, nor information technology in general. Every field occasionally partakes in a drastic shakeup. Otherwise, be become too complacent and nothing ever happens.
Ubuntu recognized the potential user experience improvements — improvements in how users engage the operating system. Not minor tweaks, not smoothing out rough edges, but an exorbitant change in the fundamental workflow. Ubuntu introduced Unity as an enhanced desktop experience. Not a new desktop environment, but a guise for the traditional Gnome 2 environment.
I was intrigued by this idea and was looking forward to what Unity would look like and how it would change my daily routine — hopefully for the better.
The failed experiment
Once the shock wore off — the shock of my desktop being transformed into something completely foreign — I started to familiarize myself with Unity. At first, it seemed like it had potential. While I was still acquainting myself with the new Ubuntu, I started to listening to some of the frustrations voiced by the Ubuntu user community. The unanimous question about Unity seemed to be how do I turn it off?
Hearing almost nothing good about this new environment, aimed at making life easier for users, I found it difficult to ignore. Granted, many complaints about Unity I was taking in were a little nit-picky and couldn't relate to. So I carried on, determined to change how my desktop worked for the better.
I must say, I admire the ambition behind the project — Unity definitely had potential but there were just too many minor issues. Aside from the bugs, Unity just didn't mesh well — didn't feel like part of the desktop. So more than just subtle bugs — Unity was a failed experiment in desktop experience. Once I switched back to Gnome 2, in it's traditional form, I felt home again. It was like I had gone on a vacation and had everything go wrong. Switching to Gnome 3 felt like a permanent vacation.
Almost, getting there...
I used the traditional Gnome 2 environment happily for about four months after turning Unity off. Then my restlessness desire for change kicked in again. I knew Gnome 3 had been released, why couldn't I try it out? It seemed like the logical evolution for my desktop environment. Luckily, I found a guide that helped me get Gnome 3 going in about an hour.
This was last week, so I'm still a new citizen here. Gnome 3 has a semblance to Unity only it doesn't feel like an addition to the desktop. The enhancements in Gnome 3 truly feel like part of the whole experience.
One common goal both Unity and Gnome 3 have is to better utilize the screen space. This means that you don't have a static task bar that shows the user all their currently open windows. The idea instead is to only show the currently running applications when it really matters. Like when I want to switch windows. In Gnome 3, I just click activities in the top left of my screen. This gives me a nice preview of what I have open at the moment.
Let's say I want to launch a new application. I can click activities again to see my favorites pane where I've added my commonly used applications. However, there is also the application menu, beside my currently open windows. I can click here to browse applications by category. This is handy if I don't know off hand the name of the application I want to run. Alternatively, when you click activities, you can just start typing the name of the application — this will bring up matches for you automatically. I've found this to be an incredibly powerful feature. I hardly ever use the favorites pane in favor of just typing a few characters and hitting enter to launch something.
In this era of streamlined desktop environments — one where space is of virtue, it's sometimes difficult to find your way around. I don't think these radical changes brought on by Unity and Gnome 3 are workflow defects, just something new and different. We've been using the standardized desktop layout for a really long time. So even if this is the sub-optimal approach to desktop computing, it's what we're used to. We've grown attached to the way we do things in our local environments, I know I have. Change is difficult, but Gnome 3 makes it a little less painful. It isn't perfect, but I truly believe it is a step in the right direction.
Friday, September 9, 2011
Isomorphic Widgets
Can two different widgets show the same data? Why would two different widgets want to display the same information? Because they look different to the user — two widgets displaying the same information suggest a new visual perspective on that data.
Is it really that relevant — contrasting presentations of the same thing? Indeed, any user wants to see information manifest in a meaningful way. Too much choice given to the user is unhealthy. Especially if what we're seeking is a consistent experience. Radical change between widgets that display the same thing is obstructive to say the least. But subtle changes in how the data looks — it's demeanor — might actually give the user a better sense of freedom.
Consistency, consistency, consistency
Why is it that user interface elements must be consistent with one another? Because the user is going to expect the next page, or the next pane, or the next tab to work the same as the previous one. Imagine navigating though the various screens of an application — none of them remotely resembling their siblings. This would be a royal pain. You learn how to use an application by getting familiar with one aspect, say the settings page, then conquering what lies ahead. If the characteristics of that screen don't carry forward, the experience can be disheartening.
Consistency means predictability. If you can't guess what the application is going do, or at least come close, it doesn't feel intuitive. Knowing the general layout, what each individual widget does, how to get somewhere specific — all things the user expects. Consistency is a form of user interface documentation — it says "take a look around, everything else you can't see right now isn't much different". Similar to Python code, the user interface can, and should, be self-documenting.
A consistent look and feel also has repercussions outside of the application too. Sure, it's great that they're using it for something useful — they've obviously found value in your stuff. But what about future releases of the software? This is where things can get tricky — downright messy in some instances. Because if you've done a good job in crafting a consistent, easy-to-use portal, any change has the potential to extirpate the user's routine.
Developers shouldn't have to fear this though, because if you've been aggressively consistent from the get go, you've made life easier for yourself when it comes to updating your code and making it available for all to enjoy. Just stick with what they're going to expect. Creating a uniform user experience means that you're establishing a standard for what goes into a release.
Layout, layout, layout
Being thoroughly consistent with your user interface design doesn't mean that every screen should look identical. That would negate the need for having more than one screen. The most important component to be consistent with is the general layout — and how it is navigated.
The layout of a screen might be considered a container — an object responsible for where smaller widgets are placed. A container is like a groomsman at a wedding ceremony — placing the guests in their appropriate positions as they arrive. You wouldn't want one screen to have smaller widgets stacked on top of one another only to move to the next screen where widgets are side by side at the top. Basic stuff, but important. If you can get the top-level layout right, you've got a lot more freedom to play around with smaller widgets.
Smaller widgets, inside containers, don't necessarily need to be uniform with every other widget on the screen. But they do need to look like they belong there. It's easy for something like a button or a table to look out of place. And this is often how things look as code is being developed. We're then able to clean up the layout once the functionality is ready.
Design freedoms
All this talk of consistency and uniform layout and user expectations makes user interface design sound like a chore instead of an artistic exercise. It doesn't need to be that way — user interface design is an art form and to do art we need some degree of freedom. Unlike other art forms, user interface design rules are a little stricter. Users don't judge the quality of applications by staring at screen shots — they judge it by how well it works. They need to engage it — the user interface is the steward — dressed up in a nice suit.
The nagging question is how can we make our user interfaces look as good as they possibly can while abiding by strict consistency rules? We can make beautiful widgets — they key is to design from the top down. Design an elegant layout and colour scheme — something generic that'll work for more than just one application. The consistency rules with user interface development should never be hindered by the application you're building.
Having said that, at the beginning of your project, don't even bother with the rules of consistency. Just throw together something you think looks good. Play with colours, fonts, and shapes. Get the overall theme looking the way you're happy with. Use the start of a project as an opportunity to get creative with design freedoms — then buckle down and evaluate your design against consistency rules to see what works and what doesn't.
User freedoms
We've looked at what it means to be consistent and how we can work around these rules to get creative with making something that'll look like it's alive — not something that looks like accounting software a financial institution uses. But what about the users? Should they get a say in how things work? Must desktop software has some degree of configuration with regard to appearance — they can change the colours, the font, borders, etc. What if they don't like the layout of a particular screen or the overall layout for that matter?
This is where isomorphic widgets would come in handy — widgets that can change appearance while still presenting the same data to the user. Obviously this is isn't a good idea for some widgets — a button is a button and a text input is a text input. But container objects — widgets that organize the overall layout of a screen — these might be subject to user preferences.
A good example of this is a tabbed layout versus an accordion layout. The jQuery UI tabs and accordion widgets are both used in this manner — to organize smaller components and to accommodate navigation. As far as the user is concerned, tabs and accordions aren't all that different — they both serve the same purpose, they just use different techniques to display and navigate. But the crux of both widgets are the same — to group related information.
I see an opportunity with both the tabs and the accordion widget — each has the potential to transform from one into the other and back again. Not only would this be valuable as far as the user is concerned — having the ability to control which layout they prefer — but also from a development perspective. If you're easily able to switch between the two presentations and evaluate which better suites the application, the more you're able to contemplate the alternatives.
The challenge being that right now both widgets require fundamentally different HTML markup to create the widget. So switching from one widget to the other requires a modification of the DOM before that can happen. Obviously the two widgets don't support the same feature set but at their most basic presentation levels, the two are highly isomorphic. Were they to support similar markup, switching between the two either at runtime or development time would be a practical endeavor.
Is it really that relevant — contrasting presentations of the same thing? Indeed, any user wants to see information manifest in a meaningful way. Too much choice given to the user is unhealthy. Especially if what we're seeking is a consistent experience. Radical change between widgets that display the same thing is obstructive to say the least. But subtle changes in how the data looks — it's demeanor — might actually give the user a better sense of freedom.
Consistency, consistency, consistency
Why is it that user interface elements must be consistent with one another? Because the user is going to expect the next page, or the next pane, or the next tab to work the same as the previous one. Imagine navigating though the various screens of an application — none of them remotely resembling their siblings. This would be a royal pain. You learn how to use an application by getting familiar with one aspect, say the settings page, then conquering what lies ahead. If the characteristics of that screen don't carry forward, the experience can be disheartening.
Consistency means predictability. If you can't guess what the application is going do, or at least come close, it doesn't feel intuitive. Knowing the general layout, what each individual widget does, how to get somewhere specific — all things the user expects. Consistency is a form of user interface documentation — it says "take a look around, everything else you can't see right now isn't much different". Similar to Python code, the user interface can, and should, be self-documenting.
A consistent look and feel also has repercussions outside of the application too. Sure, it's great that they're using it for something useful — they've obviously found value in your stuff. But what about future releases of the software? This is where things can get tricky — downright messy in some instances. Because if you've done a good job in crafting a consistent, easy-to-use portal, any change has the potential to extirpate the user's routine.
Developers shouldn't have to fear this though, because if you've been aggressively consistent from the get go, you've made life easier for yourself when it comes to updating your code and making it available for all to enjoy. Just stick with what they're going to expect. Creating a uniform user experience means that you're establishing a standard for what goes into a release.
Layout, layout, layout
Being thoroughly consistent with your user interface design doesn't mean that every screen should look identical. That would negate the need for having more than one screen. The most important component to be consistent with is the general layout — and how it is navigated.
The layout of a screen might be considered a container — an object responsible for where smaller widgets are placed. A container is like a groomsman at a wedding ceremony — placing the guests in their appropriate positions as they arrive. You wouldn't want one screen to have smaller widgets stacked on top of one another only to move to the next screen where widgets are side by side at the top. Basic stuff, but important. If you can get the top-level layout right, you've got a lot more freedom to play around with smaller widgets.
Smaller widgets, inside containers, don't necessarily need to be uniform with every other widget on the screen. But they do need to look like they belong there. It's easy for something like a button or a table to look out of place. And this is often how things look as code is being developed. We're then able to clean up the layout once the functionality is ready.
Design freedoms
All this talk of consistency and uniform layout and user expectations makes user interface design sound like a chore instead of an artistic exercise. It doesn't need to be that way — user interface design is an art form and to do art we need some degree of freedom. Unlike other art forms, user interface design rules are a little stricter. Users don't judge the quality of applications by staring at screen shots — they judge it by how well it works. They need to engage it — the user interface is the steward — dressed up in a nice suit.
The nagging question is how can we make our user interfaces look as good as they possibly can while abiding by strict consistency rules? We can make beautiful widgets — they key is to design from the top down. Design an elegant layout and colour scheme — something generic that'll work for more than just one application. The consistency rules with user interface development should never be hindered by the application you're building.
Having said that, at the beginning of your project, don't even bother with the rules of consistency. Just throw together something you think looks good. Play with colours, fonts, and shapes. Get the overall theme looking the way you're happy with. Use the start of a project as an opportunity to get creative with design freedoms — then buckle down and evaluate your design against consistency rules to see what works and what doesn't.
User freedoms
We've looked at what it means to be consistent and how we can work around these rules to get creative with making something that'll look like it's alive — not something that looks like accounting software a financial institution uses. But what about the users? Should they get a say in how things work? Must desktop software has some degree of configuration with regard to appearance — they can change the colours, the font, borders, etc. What if they don't like the layout of a particular screen or the overall layout for that matter?
This is where isomorphic widgets would come in handy — widgets that can change appearance while still presenting the same data to the user. Obviously this is isn't a good idea for some widgets — a button is a button and a text input is a text input. But container objects — widgets that organize the overall layout of a screen — these might be subject to user preferences.
A good example of this is a tabbed layout versus an accordion layout. The jQuery UI tabs and accordion widgets are both used in this manner — to organize smaller components and to accommodate navigation. As far as the user is concerned, tabs and accordions aren't all that different — they both serve the same purpose, they just use different techniques to display and navigate. But the crux of both widgets are the same — to group related information.
I see an opportunity with both the tabs and the accordion widget — each has the potential to transform from one into the other and back again. Not only would this be valuable as far as the user is concerned — having the ability to control which layout they prefer — but also from a development perspective. If you're easily able to switch between the two presentations and evaluate which better suites the application, the more you're able to contemplate the alternatives.
The challenge being that right now both widgets require fundamentally different HTML markup to create the widget. So switching from one widget to the other requires a modification of the DOM before that can happen. Obviously the two widgets don't support the same feature set but at their most basic presentation levels, the two are highly isomorphic. Were they to support similar markup, switching between the two either at runtime or development time would be a practical endeavor.
Labels:
isomorphism
,
jqueryui
,
layout
,
widget
Thursday, September 8, 2011
Themes: The New Web Resource
Web resources are an integral part of web applications. So what exactly is a web resource? A web resource, generally speaking, is anything returned by an HTTP request. For example, HTML pages are the quintessential web resource. But there are other resource types too — images, CSS style sheets, etc. The browser depends on these resources to properly render the page for the user. So in this sense, what the user sees is actually a decoupled collection of smaller resources.
A few resources are more prevalent than others — HTML, CSS, Javascript. But the fact of the matter is that anything can be a resource — data a remote agent solicits or modifies. We're not limited to what we can serve — can make available to clients. There is no predefined set of resource types.
With the ever growing complexity of applications, the limitless dependencies required to make the thing work — introducing new composite resource types is a foremost advancement toward a better web. Themes are like web pages — a composite type of resource — one that'll be ever more germane to web applications over the next couple years.
Why resources?
So why do we call the things we retrieve with HTTP requests resources? Why not call them web objects or files? The term resource has more to do with the client software than the actual resource itself. The term resource reflects the fact that what the client is fetching is something it needs to function correctly. A dependency of sorts. For example, your television makes use of a digital content stream resource.
The term resource is especially useful when we're describing stuff that has to do with the web. Things that live on the web. The web is called the web because it's interconnected. The the nodes in this graph are the resources.
When we're talking about a particular site, we're more inclined to refer to resources by their type — the page, the image, the flash, the video. But when we're talking on a pure HTTP web-as-hypermedia level, we're better with the ambiguity resources suggest. If some application has an API that lists resources, and an API that retrieves a specific resource, we can design the client around those concepts. Resources are an architectural design idiom while specific resource types describe specific resource attributes.
Themes are abstract
Up until now, we've only touched upon the most general ideas of what makes a resource on the web. Put simply, it's any web-accessible data — you can retrieve it by issuing a GET request. But the client must know about the resource's URI — where is it? Where does the client get such information? From other resources that know about it — this is the interconnectedness that makes the web so powerful.
Now that we have this resource, how does the client know what to do with it? The web browsers people use to surf the web on a daily basis know how to interpret dozens of resource types. In HTTP terms, the resource type is the content type, usually specified in the response headers. If the client knows what the resource contains — it's structure — it can make use of it.
Imagine getting a CSV row with twenty columns in it. Suppose you've hadn't received any schema for this data. You might be able to make sense of some things in the data be deriving their meaning, but you're essentially playing a guessing game. Without a standard (schema), making use of web resources is a lost cause. Web standards dictate a common set of rules so that browsers know how to display information. This is how the browser knows that a CSS web resource is used to alter the appearance of another — the HTML page.
The HTML page and the CSS stylesheet are so commonplace that we hardly think of them as abstract anymore — but they are. They're a simplified set of instructions — more abstract than saying "this group of pixels should be positioned here and should be coloured blue". Humans know how to make sense of higher-level instructions that hide the low-level details.
But even with high-level languages like those of HTML and CSS — languages that hide the messy stuff — we're still able to build applications that are incredibly difficult to comprehend let alone maintain. Web sites and web applications are getting bigger and bigger — there is a cost to that volume. Complexity means longer development time and or more development resources.
Themes are the next level up on the abstraction ladder. A theme is simply the appearance of the site — like how desktop themes let users change the appearance of their local environment. Themes are more abstract than CSS styles because of the standards imposed on them — the same style rules are found in each theme — only the properties change.
Nothing new, just improved
You might be wondering what exactly sets themes apart from any other typical web resource we're used to. Like CSS style sheets. That is what themes are after all — a collection of styles and images. Both of these things we're used to seeing in every web page we visit.
But unlike your typical CSS that we're used to, themes carry a standardized interface HTML pages can utilize. The jQuery UI project really pioneered themes — the new resource type that we've come to expect. This is how we're able to achieve a consistent look and feel across all our applications. The standard theme interface allows this because the applications that use them must adhere to the theme styles.
Themes simply tie together older, more familiar resources that we're used to. They're more abstract, enabling us to build better user interfaces for the web. So are they justified in being referred to as a new resource type? I think so.
A few resources are more prevalent than others — HTML, CSS, Javascript. But the fact of the matter is that anything can be a resource — data a remote agent solicits or modifies. We're not limited to what we can serve — can make available to clients. There is no predefined set of resource types.
With the ever growing complexity of applications, the limitless dependencies required to make the thing work — introducing new composite resource types is a foremost advancement toward a better web. Themes are like web pages — a composite type of resource — one that'll be ever more germane to web applications over the next couple years.
Why resources?
So why do we call the things we retrieve with HTTP requests resources? Why not call them web objects or files? The term resource has more to do with the client software than the actual resource itself. The term resource reflects the fact that what the client is fetching is something it needs to function correctly. A dependency of sorts. For example, your television makes use of a digital content stream resource.
The term resource is especially useful when we're describing stuff that has to do with the web. Things that live on the web. The web is called the web because it's interconnected. The the nodes in this graph are the resources.
When we're talking about a particular site, we're more inclined to refer to resources by their type — the page, the image, the flash, the video. But when we're talking on a pure HTTP web-as-hypermedia level, we're better with the ambiguity resources suggest. If some application has an API that lists resources, and an API that retrieves a specific resource, we can design the client around those concepts. Resources are an architectural design idiom while specific resource types describe specific resource attributes.
Themes are abstract
Up until now, we've only touched upon the most general ideas of what makes a resource on the web. Put simply, it's any web-accessible data — you can retrieve it by issuing a GET request. But the client must know about the resource's URI — where is it? Where does the client get such information? From other resources that know about it — this is the interconnectedness that makes the web so powerful.
Now that we have this resource, how does the client know what to do with it? The web browsers people use to surf the web on a daily basis know how to interpret dozens of resource types. In HTTP terms, the resource type is the content type, usually specified in the response headers. If the client knows what the resource contains — it's structure — it can make use of it.
Imagine getting a CSV row with twenty columns in it. Suppose you've hadn't received any schema for this data. You might be able to make sense of some things in the data be deriving their meaning, but you're essentially playing a guessing game. Without a standard (schema), making use of web resources is a lost cause. Web standards dictate a common set of rules so that browsers know how to display information. This is how the browser knows that a CSS web resource is used to alter the appearance of another — the HTML page.
The HTML page and the CSS stylesheet are so commonplace that we hardly think of them as abstract anymore — but they are. They're a simplified set of instructions — more abstract than saying "this group of pixels should be positioned here and should be coloured blue". Humans know how to make sense of higher-level instructions that hide the low-level details.
But even with high-level languages like those of HTML and CSS — languages that hide the messy stuff — we're still able to build applications that are incredibly difficult to comprehend let alone maintain. Web sites and web applications are getting bigger and bigger — there is a cost to that volume. Complexity means longer development time and or more development resources.
Themes are the next level up on the abstraction ladder. A theme is simply the appearance of the site — like how desktop themes let users change the appearance of their local environment. Themes are more abstract than CSS styles because of the standards imposed on them — the same style rules are found in each theme — only the properties change.
Nothing new, just improved
You might be wondering what exactly sets themes apart from any other typical web resource we're used to. Like CSS style sheets. That is what themes are after all — a collection of styles and images. Both of these things we're used to seeing in every web page we visit.
But unlike your typical CSS that we're used to, themes carry a standardized interface HTML pages can utilize. The jQuery UI project really pioneered themes — the new resource type that we've come to expect. This is how we're able to achieve a consistent look and feel across all our applications. The standard theme interface allows this because the applications that use them must adhere to the theme styles.
Themes simply tie together older, more familiar resources that we're used to. They're more abstract, enabling us to build better user interfaces for the web. So are they justified in being referred to as a new resource type? I think so.
Subscribe to:
Posts
(
Atom
)