Friday, April 29, 2011
Statistical Objects
Tuesday, March 2, 2010
Exceptional Development
These exception hierarchies can grow to be quite large, even in production systems. This makes sense if we want to use the exception handling mechanism in a polymorphic way. We handle all exceptions at one level of the hierarchy, including all descendant exceptions, while ignoring all exceptions at a higher level up.
These hierarchies allow us to reason about what as gone wrong. So using an aggressive approach to exception handling during initial development might make a lot of sense. Construct a list of every conceivable exceptional path that isn't part of the successful path. Generalize some of the exceptions so you avoid unnecessary duplication.
With this first initial exception hierarchy, you can pound out a first iteration quickly. The fact that none of these exceptions in the hierarchy are raised is an indicator that the iteration is complete.
Friday, October 16, 2009
Python Super Classes
Not all object-oriented languages support it, but multiple inheritance is another form of inheritance what allows developers to say class A "is a kind of" class B "and is also a kind of" class C. The Python programming language does support multiple inheritance and can support designs that employ the principle when needed.
Opponents of multiple inheritance say that it is an unnecessary feature of object oriented languages and in most cases, they are correct. Not necessarily correct about the fact that multiple inheritance shouldn't be a language feature, but about the design itself. Like anything else, multiple inheritance can be abused and actually hurt the software. Most of the time, it isn't needed and something more simplistic in design terms is ideal.
Consider the following class hierarchy. Here we have a Person class that acts as the root of the hierarchy. Next, we have an Adult and a Remote class, both of which inherit directly from Person. Finally, the Student class inherits from both Adult and Remote. The Student class uses multiple inheritance.
This is an example of where multiple inheritance may come in handy. The Remote class represents something that isn't local. This could be a Student or something else in the system. Since it is required that Student inherit from Adult, it makes sense that it also be able to inherit from Remote. A student can be both things.
Below is an example of this class hierarchy defined in Python. The super() function really helps us here because the Student class would otherwise need to invoke the individual constructors of each of its' super classes. Not only is this less code, it is also more generic of a design. All Student instances base class constructors will continue to be invoked correctly, even as these base classes change.
#Example; Using the super() function.
#Root class.
class Person(object):
def __init__(self):
super(Person, self).__init__()
print "Person"
#Adult class. Inherits from Person.
class Adult(Person):
def __init__(self):
super(Adult, self).__init__()
print "Adult"
#Remote class. Inherits from Person.
class Remote(Person):
def __init__(self):
super(Remote, self).__init__()
print "Remote"
#Student class. Inherits from both Adult and Remote.
class Student(Adult, Remote):
def __init__(self):
super(Student, self).__init__()
print "Student"
#Main.
if __name__=="__main__":
#Create a student.
student_obj=Student()
Tuesday, July 7, 2009
Leaky Abstractions
The entry also discusses "leaky" abstractions. What exactly is a "leaky" abstraction? In object-oriented software development, a leaky abstraction can be viewed as an abstraction that doesn't hide underlying problems or inconsistencies. One of the key principles of object-oriented software development is encapsulation, or information hiding. So, it is not unusual for a given high-level software abstraction to use low-level functionality under the covers. This is exactly where the leaks can occur. Technology is almost never perfect, especially when attempting to design code that will run on multiple platforms. If this isn't taken into consideration, leaks will occur. A developer could design the worlds most pristine abstraction that could end up leaking because he didn't consider a subtlety in the underlying technology encapsulated within the class.
The entry uses an object-relational mapper to illustrate an abstraction leak. This has become a popular abstraction for developers in recent years and the problems caused by it are apparent across most if not all software that provides this technology. This particular problem would be an example of a solution domain abstraction leak since the abstraction applies to any business domains using it. One may argue that there exist countless stable software solutions that use object-relational mapper technology and I would agree. I would argue that these projects also had to implement there own niche object-relational mapper abstractions on top of the third party packages just to make them functional. And there is nothing wrong with this because these projects now contain abstractions that do not leak. If this additional abstraction layer weren't implemented, it is nearly impossible to discover where the problem originated, hence the term leak. These types of abstraction leak bug-hunting sessions aren't all that different from memory leak bug-hunting sessions.
In addition to the solution solution domain abstraction leak category, which the object-relation mapper problem falls under, there can also be leaks associated with problem domain abstractions. If the underlying business logic is not fully realized by the abstraction, it can leak in mysterious ways. Abstraction leaks can be as serious a bug as a memory leak and be just as difficult to locate and correct. The main difference being that once a memory leak has been fixed, it is fixed. This is a low-level solution domain issue. Fixing an abstraction leak can have adverse effects on the abstraction itself since the quality of the abstraction matters. It is less-than-ideal to patch an abstraction. Especially in the problem domain.
Wednesday, May 13, 2009
Two Ways to Visualize Method Invocations
Method invocations can be visualized as the sending of a message. In this abstraction, the instance that makes the invocation can be thought of as the sender. The instance that implements the method can be though of as the receiver. The method name and method parameters can collectively be thought of as the message. This approach is illustrated below.
An alternative way to visualize method invocations is as the publishing of an event. In the event publishing abstraction, the instance that implements the method can be thought of as the subscriber. The instance that invokes the method can be thought of as the publisher. The method name and the method parameters can collectively be thought of as the event. This approach, not all that different from the first, is illustrated below.
Which approach is the right one? Either. Since this is simply an abstraction visualization strategy, the right approach is the one that yields the better code, and thus, the better software. However, some developers may find the message method invocation visualization approach to be more useful when designing single, one-time method invocations. The event method invocation visualization might prove more useful when designing a polymorphic method invocation over a set of instances.
Friday, February 6, 2009
Python CPU Usage
#Python CPU usage example.
import time
class CPUsage:
def __init__(self, interval=0.1, percentage=True):
self.interval=interval
self.percentage=percentage
self.result=self.compute()
def get_time(self):
stat_file=file("/proc/stat", "r")
time_list=stat_file.readline().split(" ")[2:6]
stat_file.close()
for i in range(len(time_list)) :
time_list[i]=int(time_list[i])
return time_list
def delta_time(self):
x=self.get_time()
time.sleep(self.interval)
y=self.get_time()
for i in range(len(x)):
y[i]-=x[i]
return y
def compute(self):
t=self.delta_time()
if self.percentage:
result=100-(t[len(t)-1]*100.00/sum(t))
else:
result=sum(t)
return result
def __repr__(self):
return str(self.result)
if __name__ == "__main__":
print CPUsage()
The get_time() method will return a list of CPU numbers needed to compute the number of milliseconds the CPU has been in use for the interval we are measuring.
The delta_time() method will accept a time list returned by the get_time() method. It will then return the delta time based on the same list format.
The compute() method will calculate the percentage of CPU usage or simply return the CPU time.
To me, this makes for a more object-oriented approach. This class can also be modified to suite a different usage scenario.
Friday, October 10, 2008
Object orientation
This is a continuation of my previous object orientation discussion. There, I gave my introductory thoughts on why object is beneficial in most circumstances. Not just as a fancy paradigm buzzword but as actual sustainable design. The class provides developers a taxonomic mechanism to represent abstractions in both the problem domain and the solution domain.
Encapsulation
Encapsulation in the context of object orientation means data concealment. But why do developers want to hide the internal data structures? Moreover, in cases where the developer is working by himself on some component, they are basically hiding the data from themselves.
So why is encapsulation an important concept in object orientation? The goal behind encapsulation is to hide irrelevant details from the outside world. A real life example of encapsulation is as follows. When you drive a car, several engineering details are hidden away from the driver. All the driver wants to do is move forward. When the puts the gearshift into "drive", several complex actions are executed by complex structures. Why doesn't the driver care about any of this? Because she can accomplish her goal without this knowledge overhead.
There are two sides of encapsulation. The first side being data concealment. The second being behavioural concealment. There are times when hiding functionality from the outside world is useful. Such as when there exists a method that is only used by other methods of the same class.
The following example is Python code that does not incorporate encapsulation into the design:
class BlogEntry:
def __init__(self):
self.title=''
self.body=''
if __name__=='__main__':
blog_entry_obj=BlogEntry()
blog_entry_obj.title='Test'
blog_entry_obj.body='This is a test.'
Although by default all attributes of Python instances are publicly accessible, this example directly uses attributes of the instance. This is not good programming practice and violates the idea of an encapsulated abstraction. Here is a new implementation:
class BlogEntry:
def __init__(self):
self.title=''
self.body=''
def set_title(self, title):
self.title=title
def set_body(self, body):
self.body=body
def get_title(self):
return self.title
def get_body(self):
return self.body
if __name__=='__main__':
blog_entry_obj=BlogEntry()
blog_entry_obj.set_title('Test')
blog_entry_obj.set_body('This is a test.')
Thursday, September 25, 2008
Object orientation
I think a definition would serve its purpose here. What is object orientation? Object orientation in the context of software development is a practice that developers undertake in order to better represent abstractions. Notice I'm referring to the idea of object orientation and not the features that define an object-oriented programming language. You could, in theory, practice object orientation in a functional language. You would just need to implement the object-oriented language features using the language itself. Which doesn't gain anyone anything.
Lots of developers use functional languages today and there is absolutely nothing wrong with that it it is done right. Good design is good design. The C programming language has been around for decades and is going nowhere fast. It is cross-platform, fast, and relatively easy to program in.
C++ is the object-oriented C (an increment of C). It defines the object-oriented constructs necessary for C to be considered an object-oriented programming language. Enough of the history lesson already.
Class
The class lies at the very heart of object-orientation. The class classifies things. This makes sense in software because even when developing in a functional language, you are still implicitly modeling abstractions. For example, consider the following functional code that defines a user and some behavior that the user is capable of.
def create_user(user_name=None, password=None, is_active=None):
user={}
user['user_name']=user_name
user['password']=password
user['is_active']=is_active
return user
def is_user_active(user):
if user['is_active']:
return True
if __name__=='__main__':
user=create_user(user_name='test',\
password='123',\
is_active=True)
print 'Is the user active?',is_user_active(user)
Here we have a user abstraction that is very difficult to comprehend. Lets take a look at the equivalent object-oriented functionality.
class User:
def __init__(self, user_name=None, password=None, is_active=None):
self.user_name=user_name
self.password=password
self.is_active=is_active
def is_active(self):
return self.is_active
if __name__=='__main__':
user=User(user_name='test',\
password='123',\
is_active=True)
print 'Is the user active?',user.is_active()
Here, it is much more obvious that we are dealing with a user abstraction. In the main program, we actually create a user object. This object then encapsulates the user essence. That is, the behavior associated with the concept of a user is bound to that object. This is illustrated when we invoke user.is_active().
I'll continue this discussion as part two (or something like that) because I have much to say about other object-orientation topics.