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.
Showing posts with label iterative. Show all posts
Showing posts with label iterative. Show all posts
Wednesday, April 11, 2012
Thursday, September 24, 2009
Breaking Release Cycles
There exist today endless software methodologies, each of which, allow for differing policies on producing releases. Some methodologies allow for variable length between releases while some dictate a strict cycle length. The methodologies that follow a strict release time-line are most likely using an agile approach to software development. When using this approach, the release dates for the software are one of the, if not the most, important rules to stick to.
When using an agile approach to software development, there should be a fixed amount of time between releases. This may at first seem counter intuitive. How can a development methodology be agile if the time-line is of fixed length? Agile should support change and that is indeed one of the key benefits to using an agile approach. However, not everything can change. There has to be at least some formal rules that allow for some sort of organization. If there is nothing strict in place, the practice is flawed because nothing would ever get released. And it is the continuous releasing of software that provides the invaluable feedback that plays a huge role in the agile methodology. Take a look at some open source projects that have a six month release cycle. Sure, there is feedback from the user community, but they don't see how their feedback is reflected, which, in turn, generates more feedback and so on.
With a shorter release cycle, this feedback is reflected sooner. But what about when the agile approach is used for developing a solution for a paying customer. Does their request for some change or some feature mean that the release cycle length should be changed? In almost every case, I would say no it doesn't. They are paying you to develop software because you know how to do it and constantly pushing back release dates does not help anyone. The only exception to this rule is when it is a deal breaker. If holding up the release will prevent the loss of money, you simply do not have a choice. Otherwise, there is always a good reason one can give for not including a requested feature. This is especially easy to explain to customers when you always ship predictably and on time.
When using an agile approach to software development, there should be a fixed amount of time between releases. This may at first seem counter intuitive. How can a development methodology be agile if the time-line is of fixed length? Agile should support change and that is indeed one of the key benefits to using an agile approach. However, not everything can change. There has to be at least some formal rules that allow for some sort of organization. If there is nothing strict in place, the practice is flawed because nothing would ever get released. And it is the continuous releasing of software that provides the invaluable feedback that plays a huge role in the agile methodology. Take a look at some open source projects that have a six month release cycle. Sure, there is feedback from the user community, but they don't see how their feedback is reflected, which, in turn, generates more feedback and so on.
With a shorter release cycle, this feedback is reflected sooner. But what about when the agile approach is used for developing a solution for a paying customer. Does their request for some change or some feature mean that the release cycle length should be changed? In almost every case, I would say no it doesn't. They are paying you to develop software because you know how to do it and constantly pushing back release dates does not help anyone. The only exception to this rule is when it is a deal breaker. If holding up the release will prevent the loss of money, you simply do not have a choice. Otherwise, there is always a good reason one can give for not including a requested feature. This is especially easy to explain to customers when you always ship predictably and on time.
Thursday, August 27, 2009
Building Python Lists
Building primitive Python lists is a common task in virtually any Python application. The Python list is not unlike a traditional array in many respects, only more powerful. A common scenario is building a Python list from an iterator that yields values. In this case, each iteration adds a new element to the list being built. One method used to build Python lists using an iteration construct is the append method. This approach invokes the list append() method to append a new list element. Another approach to building Python lists is to place the iteration itself within the new list. This approach can be considered inline list building. The benefit to using the inline approach is the performance gain. The benefit to using the append method is readability when logic is required within each iteration that appends elements to the list. Below is an example illustrating both approaches.
#Example; Building Python lists.
import timeit
#Build a list consisting of ten elements using the append method.
def build_append():
list_obj=[]
for i in range(0,10):
list_obj.append(i)
#Build a list consisting of ten elements using the inline method.
def build_inline():
list_obj=[i for i in range(0,10)]
if __name__=="__main__":
#Setup timers.
t_append=timeit.Timer("build_append()",\
"from __main__ import build_append")
t_inline=timeit.Timer("build_inline()",\
"from __main__ import build_inline")
#Execute timers.
r_append=t_append.timeit()
r_inline=t_inline.timeit()
#Show results.
print "APPEND:",r_append
print "INLINE:",r_inline
print "DIFF %:",(r_inline/r_append)*100
Saturday, February 14, 2009
Custom Python iterators.
I've been experimenting with writing custom Python iterators. In Python, any sequence type can be iterated over. For example, when you say "for i in list_obj", list_obj actually returns an iterator. For this common case, the developer need not be concerned with the iterator. They know that it will always behave correctly in a for loop.
If you have a class that needs to be iterated over, you can define a custom iterator for your class as demonstrated below.
Here, we have a custom iterator defined, MyIterator. The constructor initializes the object it will iterate over as well as the counter. The __iter__() method is required to return the current MyIterator instance so the iterator can also be iterated over. Sort of like meta-iteration.
The important method is next() which returns the next item in the iteration. In this case, every time next() is invoked, we attempt to return the value of get() and increment the counter. Once there are no more items, we raise a StopIteration exception, which will gracefully exit the iteration.
Finally, you'll notice that MyClass defines a __iter__() method. This is what gives instances of MyClass that ability to be iterated over. The method simply returns a MyIterator instance.
If you have a class that needs to be iterated over, you can define a custom iterator for your class as demonstrated below.
#Example; Custom iterators.
class MyIterator:
def __init__(self, obj):
self.obj=obj
self.cnt=0
def __iter__(self):
return self
def next(self):
try:
result=self.obj.get(self.cnt)
self.cnt+=1
return result
except IndexError:
raise StopIteration
class MyClass:
def __init__(self):
self.data=["Item 1", "Item 2", "Item 3"]
def __iter__(self):
return MyIterator(self)
def get(self, index):
print "Getting item..."
return self.data[index]
if __name__=="__main__":
for item in MyClass():
print item
The important method is next() which returns the next item in the iteration. In this case, every time next() is invoked, we attempt to return the value of get() and increment the counter. Once there are no more items, we raise a StopIteration exception, which will gracefully exit the iteration.
Finally, you'll notice that MyClass defines a __iter__() method. This is what gives instances of MyClass that ability to be iterated over. The method simply returns a MyIterator instance.
Thursday, July 10, 2008
Everything should be iterative.
In software, everything should be iterative. Not only that, but the size of the set being iterated over should never be statically set in code. Functions and methods should never return a multiplicity of one. The exception in this case would be if the function simply performs some action and we are not interested in the result.
This is the backbone of extensibility in software development. As soon as you impose multiplicity limits on objects, you are essentially eliminating any chance for extension in that component. If you have some method of some object that returns another software object that is not iterated-over, the chance for that method to return a dynamically determined number of is gone.
What if the behavior caused by the result of some method invocation should differ depending on the length of the number of objects returned? This is seldom the case and you can always have alternative flows of control depending on the length of the result. This extra bit of code in extreme cases is a small price to pay for the extensibility this patter offers.
This is the backbone of extensibility in software development. As soon as you impose multiplicity limits on objects, you are essentially eliminating any chance for extension in that component. If you have some method of some object that returns another software object that is not iterated-over, the chance for that method to return a dynamically determined number of is gone.
What if the behavior caused by the result of some method invocation should differ depending on the length of the number of objects returned? This is seldom the case and you can always have alternative flows of control depending on the length of the result. This extra bit of code in extreme cases is a small price to pay for the extensibility this patter offers.
Subscribe to:
Posts
(
Atom
)