Why paint a picture, sketch a cartoon, or play an instrument? Artistic expression. Maybe there is more to these images and sounds than simply conveying how we feel. Maybe they're a communication channel, more efficient than talking or typing out the information. Depending on what you're trying to divulge, choosing the right communication channel can improve how well that information is received. This doesn't exclude communication with yourself, either.
Consider note taking — little reminders for later. It isn't the content here that's important, but rather the timeliness — it has to be now. Probably just a little scribble, utterly meaningless to someone else, but to you, it means a lot. You come across your reminder the following day, and all the context surrounding your earlier thought comes flooding back. Our minds suit our own needs best.
If we think about communication in a larger group of people, say, a software development team, things suddenly become more complicated. We're engendering the potential for ambiguity — mostly misinterpretation — unless we take the time to make ourselves clear. When we're writing code, or even just having a casual discussion about the way software should be built, we all have different angles. Our past experiences shape our opinions of software and its development.
Diagrams are an effective means to bridge differences in software development thought processes. Mostly because they're an abstract visual aid, a tool to visualize concepts. There are standards that assist us in creating consistent diagrams, such as the UML. More broadly, the aim of these standards is for it's users to construct a collection of diagrams — a model of the software system. In fact, this can sometimes take away from the value diagrams bring in advocating communication.
Problems that standards solve
The UML is the de facto standard when it comes to proclaiming what software diagrams should look like. What elements are allowed, how they're shaped, how they're connected to one another, and so on. Standards such as the UML are a worthy cause, one that I practice to the best of my ability. Understanding diagrams that someone other than yourself has created can be a strenuous exercise. Without the diagram creator's guidance, you must make sense of the meta-data in the diagram before you can truly understand the diagram's content.
This, in short, is the problem the UML solves — how do we make sense of diagram elements that describe software systems? The UML solves this problem by giving us the meta-data about our diagrams. The theory is, if Bob knows the UML, I can draw a diagram using elements found in the specification and he'll be able to interpret it without my help.
It is a good theory. It's goal at an even higher level is along the lines of unambiguous communication. I think the UML adequately meets those goals, perhaps even too profusely at times. There are elements that we're always going to use, and there are those that are hardly ever used. The abundance of different things we can represent in the UML make the language challenging to learn, but you don't need to learn the entire language. Just like you don't need to learn the English vernacular in it's entirety to communicate effectively.
Problems that standards create
With every standard ever conceived, a slew of concessions blossom as a result. Standards are standards because they're the standard way of doing something. A pattern that's beneficial to the whole instead of a subset. In the case of the UML, software development teams create diagrams to aid in communication. We now have a standard way of doing that. Any activity a team performs will impact other activities. There is really no way around that, and so, you need to strike a balance. If abiding diagramming standards means less code is written and tested, you're wandering down the wrong path.
One specific problem I have with UML doesn't have anything to do with the standard itself, but the culture it creates. That is, we have this big and powerful specification that can express everything we could ever want. And everyone understands it! Brilliant! These diagrams are obviously of the utmost value and must be preserved. I don't think this is true. It's difficult to maintain formal models of software systems. You have to make sure they reflect the current reality of the physical software. You have to coordinate with other developers to ensure your diagrams don't contradict one another. A lot of work, so where is the value?
Vast models of software systems that attempt to illuminate challenging issues with beautiful diagrams could be valuable, if they're used over and over again. For example, if your model is your project's documentation. This is rarely the case. What diagrams do best, in my opinion, is assist with the initial thought process that goes on when we're trying to solve a problem. They're a communication tool, some of which have staying power, and some don't. Valuable diagrams that you'll want to keep are fairly obvious. They're usually simple too. So if your model isn't helpful in putting thoughts about software into picture form, start focusing more on the diagrams. They're a much better tool.
Saturday, April 28, 2012
Wednesday, April 11, 2012
Too Much Consistency
Can you actually be too consistent? Is there such thing as abiding too closely to rules set forth? Put another way, consistency is really about predictability — patterns that repeat themselves. If the layout of my user profile page follows a two-column design, I should probably use two-column layouts on my blog entry pages. And on my comment pages. You know what, it wouldn't make sense not to use two-column layout anywhere on the site, right?
Consistency is merely a principle, a convenient and useful one at that. You won't be forever banished from user interface design should you decide to mix things up a little. If you feel forced to use a particular pattern just because it was used elsewhere, maybe you're pointed toward, what should we call this, flawed consistency? Anyway, if it feels and looks flawed, and the driving force are the rules of predictability, change it.
Consistency Feels Good
Is it the act of doing something consistently that feels good, or it's side-effects? Being predictable in how we work isn't easy — you often need to go out of your way to make sure you're using the right dependencies, using the right theme, following consistent naming conventions. It can be exhausting, but in the end, you've made something that permeates. Being consistent yields a feeling of producing a missing puzzle piece to help activate the larger whole. Or maybe following the given rules set forth by the team makes us consistent out of fear. The fear of standing out as the careless one, too lazy to play by the rules and make something that everyone understands.
I think consistency, and the good feeling we get from practising it, is something we can't exactly measure. I think its part of the personality trait that drives us to build software in the first place. Order out of chaos, and so on.
But let's not forget, we're seldom consistent with what we build right out of the gates. If we were, it would take forever to investigate our mild curiosities that lead to production system components. It takes time, we have to gradually evolve to become self-consistent — with our own code. It takes even longer before the stuff we're inventing becomes a seamless shape, composed of a team's efforts. So, stepping back to the pre-consistency stage of software development — where is the joy in hammering out lines that don't gel with one another? The joy is in making it work. We can be consistent to our heart's content, but it means nothing if it doesn't work.
Consistency Is Iterative
It's almost as though consistency is a side-effect of good engineering. How often do you look at ugly code that works great? Not very, I would imagine. The goal with developing software, in early iterations, is to get something working. The confidence boost necessary for continued momentum. After which, we get an icky feeling — something just doesn't seem right about the code. We've left some commented-out experiments in sections, some conventions weren't followed entirely, if at all.
This marks the beginning of an iteration whereby the consistent, clean-feeling code is established. Funny isn't it — clean code usually translates to consistent code.
And then we're back to grit mode — doing battle, using what's in our toolbox to break down obstacles. A system that doesn't oscillate between making things that work and aligning those things with sanctioned conventions is a system that fails to evolve. We have two principles at work here, both of which favour our programming habits. We have an urge to create, and an urge to cultivate. We're also perfectionists, which tends to disrupt the happy development cycle.
Consistency Can Be Disruptive
Sure, beautiful code is ideal — sought after, even. Just how much time should be spent pursuing this perfection? If it's got to be perfect, the answer is a simple one — as much time as it takes. Is there such thing as perfect software? Of course not! Getting caught up in making your software consistent in every sense of the word just isn't going to happen. Consistency is a multi-dimensional problem with software systems. You've got the code itself, which is difficult, and you've got everything else, facing the outside world. The user interface, the API, the operating system interfaces, and any other system that plays a role in the ultimate architecture of your software.
Compounding the challenge of achieving consistency in software development are the inescapable trade-offs one has to make. Time consuming as this re-factoring and general cleanup work is, there is always more to do. These tasks are investigative by nature, yielding discoveries of inconsistency that beg to be resolved.
But should they be resolved? Do you have time to upset the cycle of creation and re-factoring? Inconsistencies can in fact be left alone, it's just a simple matter of choosing your battles. That is, how serious is the inconsistency? Does it lead to difficulties for other team members and thus slow down the project velocity as a whole? Or is it one of those annoyances that just gets to you? Perhaps more importantly, evaluate the positives of not bothering with fixing an inconsistency. The most obvious benefit, of course, is that you stay on track and the cycle continues. In the long run, you're saving yourself many headaches too. Think of all the potentially unnecessary work you're eliminating over the next month and how that time can be invested differently.
Consistency is merely a principle, a convenient and useful one at that. You won't be forever banished from user interface design should you decide to mix things up a little. If you feel forced to use a particular pattern just because it was used elsewhere, maybe you're pointed toward, what should we call this, flawed consistency? Anyway, if it feels and looks flawed, and the driving force are the rules of predictability, change it.
Consistency Feels Good
Is it the act of doing something consistently that feels good, or it's side-effects? Being predictable in how we work isn't easy — you often need to go out of your way to make sure you're using the right dependencies, using the right theme, following consistent naming conventions. It can be exhausting, but in the end, you've made something that permeates. Being consistent yields a feeling of producing a missing puzzle piece to help activate the larger whole. Or maybe following the given rules set forth by the team makes us consistent out of fear. The fear of standing out as the careless one, too lazy to play by the rules and make something that everyone understands.
I think consistency, and the good feeling we get from practising it, is something we can't exactly measure. I think its part of the personality trait that drives us to build software in the first place. Order out of chaos, and so on.
But let's not forget, we're seldom consistent with what we build right out of the gates. If we were, it would take forever to investigate our mild curiosities that lead to production system components. It takes time, we have to gradually evolve to become self-consistent — with our own code. It takes even longer before the stuff we're inventing becomes a seamless shape, composed of a team's efforts. So, stepping back to the pre-consistency stage of software development — where is the joy in hammering out lines that don't gel with one another? The joy is in making it work. We can be consistent to our heart's content, but it means nothing if it doesn't work.
Consistency Is Iterative
It's almost as though consistency is a side-effect of good engineering. How often do you look at ugly code that works great? Not very, I would imagine. The goal with developing software, in early iterations, is to get something working. The confidence boost necessary for continued momentum. After which, we get an icky feeling — something just doesn't seem right about the code. We've left some commented-out experiments in sections, some conventions weren't followed entirely, if at all.
This marks the beginning of an iteration whereby the consistent, clean-feeling code is established. Funny isn't it — clean code usually translates to consistent code.
And then we're back to grit mode — doing battle, using what's in our toolbox to break down obstacles. A system that doesn't oscillate between making things that work and aligning those things with sanctioned conventions is a system that fails to evolve. We have two principles at work here, both of which favour our programming habits. We have an urge to create, and an urge to cultivate. We're also perfectionists, which tends to disrupt the happy development cycle.
Consistency Can Be Disruptive
Sure, beautiful code is ideal — sought after, even. Just how much time should be spent pursuing this perfection? If it's got to be perfect, the answer is a simple one — as much time as it takes. Is there such thing as perfect software? Of course not! Getting caught up in making your software consistent in every sense of the word just isn't going to happen. Consistency is a multi-dimensional problem with software systems. You've got the code itself, which is difficult, and you've got everything else, facing the outside world. The user interface, the API, the operating system interfaces, and any other system that plays a role in the ultimate architecture of your software.
Compounding the challenge of achieving consistency in software development are the inescapable trade-offs one has to make. Time consuming as this re-factoring and general cleanup work is, there is always more to do. These tasks are investigative by nature, yielding discoveries of inconsistency that beg to be resolved.
But should they be resolved? Do you have time to upset the cycle of creation and re-factoring? Inconsistencies can in fact be left alone, it's just a simple matter of choosing your battles. That is, how serious is the inconsistency? Does it lead to difficulties for other team members and thus slow down the project velocity as a whole? Or is it one of those annoyances that just gets to you? Perhaps more importantly, evaluate the positives of not bothering with fixing an inconsistency. The most obvious benefit, of course, is that you stay on track and the cycle continues. In the long run, you're saving yourself many headaches too. Think of all the potentially unnecessary work you're eliminating over the next month and how that time can be invested differently.
Wednesday, April 4, 2012
Appliances For The Cloud
For things that run in the cloud, I like the term appliance because it is generic. And generic is what we're after when designing stuff that runs in heterogeneous environments. Appliance is meaningful as a term because it encapsulates the notion of hardware and the raw binary that is the operating system. This is great, if we can manage to deploy bare-bone operating systems using a single appliance on multiple cloud providers. But appliance design should also take into consideration the larger business problems of the distributed application — virtual machines rarely exist in isolation.
That said, what types of problems can we solve at appliance design time? This is the challenge, because the ultimate goal would be to retain some level of flexibility for the application code once provisioned, but we also want to reuse the appliance in more than one environment. There are important factors to consider when designing appliances for the cloud, two of which I think deserve close attention.
System Requirements
When you install a piece of software on your computer, the installer is more often than not going to perform some sanity checking. Things like, "this is a x86_64 architecture, I'm not touching that" or "512MB RAM isn't going to cut it". These are the minimum requirements that affect either the software's reliability, performance, or both. Not meeting these requirements means you simply cannot expect the software to work as described.
When programmers create software systems, they consider these limitations of the architecture relative to the end user's hardware. A dominating influence in what a system can and cannot do is the hardware resources available to it. For example, if you're building a game, you would look at the consumer hardware available to your audience and aim for something that will run on a selection of those hardware platforms. If you're writing a multi-tenant web application, you're going to look at typical server hardware configurations and strive to meet those requirements.
Designing an appliance for the cloud, on the other hand, requires these same hardware considerations, but with a more adaptive attitude. Deploying to the cloud is a different paradigm than installing software on physical hardware. With traditional software systems installed on traditional hardware, there is no sense of urgency. It isn't the end of the world if, say, your current server doesn't support the required RAM by a web application you'd like use. You can take time to evaluate alternative hardware configurations, or alternative software packages. Physical hardware is a long-term investment. Therefore, it is important to achieve the right mix of system resources and software that can best utilize it. Hardware in the cloud on the other hand, is transient. As is the demand for it.
Systems deployed on cloud provider infrastructures succeed because this is the best suited environment to handle fluctuations in demand. Collective insight over the past several years has been that end users — customers — control the need for hardware resources, not the software itself. That is, unless you're deploying a large-scale autonomous analytical engine that will suck back any CPU cycles you throw at it. So let's assume that isn't the case and your software doesn't necessitate long-running idle processes in order to function. Let's assume that we have no way of predicting what our users will do, or how many of them will do it.
That being the case, our appliances will need to be replicated when the need for more hardware resources arises, due to increased activity. Can we get away with deploying copies of our application that requires at least 2GB RAM? That is, can we safely make the assumption that the cloud will give us the necessary resources? I think this is a dangerous assumption to make about provider infrastructures. Don't forget, clouds are just lots of physical machines, they cannot pack every single virtual machine, rigidly honouring their hardware requirements. But if a cloud cannot give my appliance what it wants, perhaps it will give me a counter offer of 1GB RAM. Should I take the offer?
Remember, we have a backlog of demand to fulfil at this point. The need for hardware is now, not later. Urgency trumps ideal hardware environments. So at the application level, I should be able to make use of these limited resources that can contribute to satisfying demand that is current. I don't have time to think, my application needs to react. What I can do, however, is use this scenario to my advantage when I'm designing my appliance — the fact that I need to take hardware I can get, without much vetting.
Ephemeral Existence
Uncertainty. This is what we're up against in any kind of software development. The degree to which we cannot predict the events our software must deal with scales up along with user counts. To combat this uncertainty, we try to utilize the elastic nature of cloud environments. The elasticity comes from expanding and contracting hardware resources as provisioned by our application to meet demand. So I think equal emphasis needs to be placed on the transient nature of virtual machines at appliance design time.
Another challenge with designing software appliances targeted for cloud environments is configuration. When a virtual machine instantiated from an appliance comes to life, it must inspect it's virtual hardware environment, not in great detail, but as a basic guide to what can feasibly be done. The software needs to note that the currently allocated resources can handle a given load. If not, as in the scenario where the virtual machine is operating with less-than-optimal hardware resources, the software needs to make adjustments. Perhaps it needs to adjust simple configuration values that tell the system to take on less work. On the other hand, maybe the virtual machine was provisioned with more hardware capacity than it's used to. In this case, it might be beneficial for the system to configure itself to use a greedy strategy with regard to resources simply because it can get away with it.
Above all else, appliances built for cloud environments have a whole batch of design problems to acknowledge. I would go so far as to say that appliance design is a separate design activity. But at the same time, appliance design goals — optimal performance and reuse — cannot be achieved independently of the contained software system. What is necessary, then, is an integrated strategy that places emphasis on appliance quality attributes while developing the software. We need to force important deployment questions during the software design phase that may not have been relevant in the past. Even previous releases of current software projects may not have considered these questions about cloud environments. Cloud infrastructures aren't perfect. Appliances need to handle these imperfections. The best way to do that is by adopting a strategy to accommodate the transient nature of both demand and the availability of resources.
That said, what types of problems can we solve at appliance design time? This is the challenge, because the ultimate goal would be to retain some level of flexibility for the application code once provisioned, but we also want to reuse the appliance in more than one environment. There are important factors to consider when designing appliances for the cloud, two of which I think deserve close attention.
System Requirements
When you install a piece of software on your computer, the installer is more often than not going to perform some sanity checking. Things like, "this is a x86_64 architecture, I'm not touching that" or "512MB RAM isn't going to cut it". These are the minimum requirements that affect either the software's reliability, performance, or both. Not meeting these requirements means you simply cannot expect the software to work as described.
When programmers create software systems, they consider these limitations of the architecture relative to the end user's hardware. A dominating influence in what a system can and cannot do is the hardware resources available to it. For example, if you're building a game, you would look at the consumer hardware available to your audience and aim for something that will run on a selection of those hardware platforms. If you're writing a multi-tenant web application, you're going to look at typical server hardware configurations and strive to meet those requirements.
Designing an appliance for the cloud, on the other hand, requires these same hardware considerations, but with a more adaptive attitude. Deploying to the cloud is a different paradigm than installing software on physical hardware. With traditional software systems installed on traditional hardware, there is no sense of urgency. It isn't the end of the world if, say, your current server doesn't support the required RAM by a web application you'd like use. You can take time to evaluate alternative hardware configurations, or alternative software packages. Physical hardware is a long-term investment. Therefore, it is important to achieve the right mix of system resources and software that can best utilize it. Hardware in the cloud on the other hand, is transient. As is the demand for it.
Systems deployed on cloud provider infrastructures succeed because this is the best suited environment to handle fluctuations in demand. Collective insight over the past several years has been that end users — customers — control the need for hardware resources, not the software itself. That is, unless you're deploying a large-scale autonomous analytical engine that will suck back any CPU cycles you throw at it. So let's assume that isn't the case and your software doesn't necessitate long-running idle processes in order to function. Let's assume that we have no way of predicting what our users will do, or how many of them will do it.
That being the case, our appliances will need to be replicated when the need for more hardware resources arises, due to increased activity. Can we get away with deploying copies of our application that requires at least 2GB RAM? That is, can we safely make the assumption that the cloud will give us the necessary resources? I think this is a dangerous assumption to make about provider infrastructures. Don't forget, clouds are just lots of physical machines, they cannot pack every single virtual machine, rigidly honouring their hardware requirements. But if a cloud cannot give my appliance what it wants, perhaps it will give me a counter offer of 1GB RAM. Should I take the offer?
Remember, we have a backlog of demand to fulfil at this point. The need for hardware is now, not later. Urgency trumps ideal hardware environments. So at the application level, I should be able to make use of these limited resources that can contribute to satisfying demand that is current. I don't have time to think, my application needs to react. What I can do, however, is use this scenario to my advantage when I'm designing my appliance — the fact that I need to take hardware I can get, without much vetting.
Ephemeral Existence
Uncertainty. This is what we're up against in any kind of software development. The degree to which we cannot predict the events our software must deal with scales up along with user counts. To combat this uncertainty, we try to utilize the elastic nature of cloud environments. The elasticity comes from expanding and contracting hardware resources as provisioned by our application to meet demand. So I think equal emphasis needs to be placed on the transient nature of virtual machines at appliance design time.
Another challenge with designing software appliances targeted for cloud environments is configuration. When a virtual machine instantiated from an appliance comes to life, it must inspect it's virtual hardware environment, not in great detail, but as a basic guide to what can feasibly be done. The software needs to note that the currently allocated resources can handle a given load. If not, as in the scenario where the virtual machine is operating with less-than-optimal hardware resources, the software needs to make adjustments. Perhaps it needs to adjust simple configuration values that tell the system to take on less work. On the other hand, maybe the virtual machine was provisioned with more hardware capacity than it's used to. In this case, it might be beneficial for the system to configure itself to use a greedy strategy with regard to resources simply because it can get away with it.
Above all else, appliances built for cloud environments have a whole batch of design problems to acknowledge. I would go so far as to say that appliance design is a separate design activity. But at the same time, appliance design goals — optimal performance and reuse — cannot be achieved independently of the contained software system. What is necessary, then, is an integrated strategy that places emphasis on appliance quality attributes while developing the software. We need to force important deployment questions during the software design phase that may not have been relevant in the past. Even previous releases of current software projects may not have considered these questions about cloud environments. Cloud infrastructures aren't perfect. Appliances need to handle these imperfections. The best way to do that is by adopting a strategy to accommodate the transient nature of both demand and the availability of resources.
Subscribe to:
Posts
(
Atom
)