31 March, 2007

Smells like Perl, Tastes like Python: Perl TT

My recent procurement of new employment has thrown me back into the hellish world of perl.  For those unaware, perl is the dyslexic ginger stepchild of 2400 bps modem line noise, albeit executable and fast.  Now don’t get me wrong, I’ve been coding professionally in perl since 1995, and have produced several large enterprise applications that are still in use to this very day.  


    Perl is a very capable language without a doubt however having used the language for so many years both professionally and for hobby I have become well aware of its faults and shortcomings.  This article isn’t specifically about pointing out the many issues perl has, some of which will be addressed in Perl 6 (when it eventually gets released in 2027).  Today I am only going to speak of one specific issue which is actually quasi addressed in a set of modules, all relating to the Template Toolkit.


    When coding in perl, even adhering to best practices such as those outlined in the excellent book by the one and only Damien Conway, author of the more notable “Object Oriented Perl”, one still finds perl problematic due to too much adherence to the ‘there’s more than one way to do it’ mantra.  The constructs are very low-level language based, which makes sense given perl’s humble beginnings but ugly none the less.  Some languages which have come into existence after perl have corrected this shortcoming and as previously stated, perl is moving towards correcting some of its ugliness, though a bit late.


    The current leading language which not only matches perl’s power in many areas, while exceeding perl’s abilities in others is Python.  Its focus on clean form through visually enforced coding constructs along with a more natural syntax which closely follows not only spoken speech but though processes is a testament to language advancements.  Which brings us to my main focus of this article, clean syntax in the style of Python, within a perl application.


    The perl Template Toolkit by Andy Wardley is the definitive all around powerhouse of template creation systems available within perl.  There are many others available but they all pale in comparison especially when you take into consideration the multitude of uses, formats and arenas in which Template Toolkit is competent. This is no mere mail merge replacement library, even though it will do just that exceedingly well.  The toolkit is much more than that, mainly due to its wonderful flexibility in its meta language utilised for in-template logic.


    This language within a language is also where I happen to draw its direct link to Python whether intentional or not.  Good design shines through and it just happens that the aforementioned comparison is dead on.  Let us begin with a sample of what I’m talking about but reviewing a simple .tt template from the Template Toolkit website.


    [% FOREACH team = teams -%]

    [% team.name %] [% team.played -%] 

    [% team.won %] [% team.drawn %] [% team.lost %]

    [% END %]


    All of the above would be located in a .tt template file.  A dictionary (a.k.a. associative array/hash) is passed called “teams”, containing the named elements of name, played, won, drawn and lost respectively with their associated values.  Unlike perl’s “c” style referencing methodologies which is fine and dandy for shell scripting or c programming it is by no means as clean as the more appropriate referencing styles utilised by most modern languages, specifically object oriented languages using the dot format.  As a side note, perl’s object system was ripped almost verbatim from Python, though poorly implemented (e.g. implemented with perl’s tmtowtdi mind-set as opposed to a proper object focus with structure and stringency.)  


    The above code is clean and simple, much like Python.  The only exception is the punctuation, which is only necessary as delimiters for the meta language.  Thanks to this cleaner approach taken by the Template Toolkit system, we can allow the logic to be cleaner by limiting the perl to only the minimal amounts thus ending up with cleaner overall code, especially handy in the world of cgi and/or form processing.  


    Let us face facts, of the following, how would you range readability from easiest to hardest.


    Python:

    for team in teams:

        print team.name, team.played + ‘-’

        print team.won, team.drawn, team.lost


     Template Toolkit:                                     

     [% FOREACH team = teams - %]

     [% team.name %] [% team.played -%]

     [% team.won % ] [% team.drawn %] [% team.lost %]

     [% END %]


    Perl:                                                               

    foreach my $team (@teams) 

    {

        print “$team{‘name’} $team{‘played’} -\n”;

        print “$team{‘won’} $team{‘drawn’} $team{‘lost’}\n”;

    }


    The above Python code is simple to understand, even by non-programmers.  The Template Toolkit version while a little messier due to the punctuation is still rather clear cut and simple to read, while the perl version adds a significant amount of unnecessary punctuation.  What this all comes down to is that if you have to code in a perl environment, there is now a way in which you can produce a cleaner codebase, mainly by keeping the data display layout and logic within .tt template files.  


    So I commend Andy Wardley and all of those who assisted with this wonderful module (and its associated add-ons) in doing what Larry Wall and crew have been unwilling to do thus far within perl.  Dictate flexible standards which avoid the ugliness which has now grown synonymous with perl.  If you find yourself stuck in a perl environment, you now have some solace in a place to take refuge courtesy of the Template Toolkit.  


    Oh, and for those of you who have moved on to one of the the languages of choice at google, Python, there is the ever flexible Cheetah template framework.

22 March, 2007

My Adventures in Software Engineering Consulting

  Starting in August of 2006 I ventured into the world of independent Software Engineering contracting.  Having just completed my previous salaried tenure at a financial firm, and a small side stint for a Fashion magazine as a favour to the owner(s)., I came upon a new offering.  I was hesitant at first because it was a 1099 contract job, a realm I’d never ventured into before in my professional career, and as such the time had apparently come. 


    The position was simple, the company in question was a contractor to a large retail clothier whose name rhymes with ‘Hurlington Boat Factory’ and is located in a town in New Jersey possessing a similar sounding name.  The CEO of the contracting firm requested specifically someone with considerable experience in Python who could build a real-time return transactions processing system which would utilise both XML and Oracle 10g.  While I have a strong dislike (along with many other software engineers) for XML, the reality of getting paid decent money for coding 100% in Python was all that I needed to hear.


    I have to say that I was excited not only because of the prospect of a Python pure coding environment but that I would be working initially and then periodically out of a satellite office in Cherry Hill.  This was exciting because for the first time in my decade plus career, I was finally in a scenario where I was writing code for a company whose primary purpose was producing JAVA software applications for sale.  The office in Cherry Hill consisted primarily of the CEO, a lead developer and a secondary developer.  There were several other individuals who would at times utilise the office including the owners, project managers and other associates of various roles, but ultimately it was an office with other competent coders one of those being quite the master of Cold Fusion technologies.  


    After my first few weeks on site in the Cherry Hill office it was time to start working on-site at Hurlington’s headquarters along with the only other consultant coding in Python.  This was the beginning of a very enjoyable period in the contract due to the excitement of the project and the joy and experience of worthing with another Pythonista.   


    The details of the project are much like any other project you might encounter when modelling a new project off of a customer version produced for a specific client.  It got ugly for a while due to the multiple aspects of the project including client systems which needed to be integrated for proper functioning along with an existing array of registers distributed nationwide and a database number records approach a half a billion entries.  The normal in fighting and finger pointing existed but it was all worked out in the end with a finished product delivered and a contract satisfied 100 percent. 


    The only issues encountered which left a bad taste in my mouth were those pertaining to a clueless project manager who regardless of his claim of years of experience was apparently lacking considerably outside of his realm of Oracle, which caused unnecessary attitude due to his ignorance of coding and APIs.  There were other issues dealing primarily with suits, but I doubt that this specific issues varies much anywhere.  Suits and Engineers rarely if ever mix, let alone get along except on a faux-cordial level.   The ultimate end of the contract was due to the project portion I was responsible for coming to fruition, even though I was already working on leaving regardless.   It wouldn’t have mattered much anyway given that the main contracting company is located up north in the centre of New England and are in the process of relocating everyone to that locale, an act which I am unwilling to do.


    I do like certain aspects of software consulting, but given that there is a considerable amount of extra taxes which must be held aside, some unholy hours which must be adhered to for the purposes of meeting quite strict time lines, and the reality of being a second class citizen in the work environment (or 3rd class in my case as a sub-contractor).  It all comes to an end in two days and I go back to a normal, preferred work environment in five days when I start up in a salaried position again working for a web host writing a multitude of applications and revisions of existing software, in a nice relaxed geek environment, also in New Jersey, but this time around, I’m excited to not be a consultant.   At least for the time being.

28 June, 2006

Rethinking Real-World Object Models in Simulations

    Over the past quarter century I have routinely pondered back to the time of my childhood and early experiences with interactive fiction text-based adventure games.  Chances are that if you were involved with computers  at any point prior to the mid-eighties, you have experienced what I speak of.  If not, maybe you experienced multi-user dungeons (MUDs) in your college or bulletin board (BBS) years.


    In many cases these ‘games’ were written in the low level language du jour, such as ‘C’, or in a custom language like ‘Inform’ (in the case of Infocom games) which was also written in ‘C’.   There were languages which would’ve been better suited for these games/simulations, object oriented programming (OOP) languages such as Smalltalk, or Objective-C, but they were generally not utilised as such.  


    Recently in my workplace I have been developing full time (for the past couple of years) in Python, a wonderful high level language written by Guido van Rossum which is a proper OOP language.  As such, the idea of writing a simulation (not a ‘game’ per se) which would allow me to focus on not only how one would model the real world (to a certain depth), but as an exercise in python objects.  


    While the code is still an ongoing side work of mine, I am posting the parent class (SimObject) and it’s associated child classes (Place, Person and ExitObject) for review by those who are interested.  Please note that due to certain conflicts with word press, proper pythonic indentation (required for execution) is not established as such.  



#####################################################

#                            S  I  M  O  B  J  E  C  T       C   L   A   S   S                          #

#####################################################


class SimObject:

    object_master_list=[]

    def __init__(self,

                object_id = 0,

                object_sku = 0,

                short_description = 'Short Description',

                long_description = 'Long Description',

                name = 'Name',

                weight = 1.0,

                height = 1.0,

                width  = 1.0,

                depth  = 1.0,

                visible  = True,

                closed   = False,

                contents = [],

                stack    = []):

        self._object_id         = object_id

        self._object_sku        = object_sku

        self._short_description = short_description

        self._long_description  = long_description

        self._name              = name

        self._weight            = weight

        self._height            = height

        self._width             = width

        self._depth             = depth

        self._visible           = visible

        self._closed            = closed

        self._contents          = []

        self._stack             = []

        self.object_master_list.append(self)

        


    def getObjectById(self,object_id):

        for sim_objects in self.object_master_list:

            if sim_objects.getObjectId() == object_id:

                return sim_objects

                

    def addContents(self,item):

        try:

            self._contents.append(item)

            return True

        except:

            return False


    def addToStack(self,item):

        try:

            self._stack.append(item)

            return True

        except:

            return False

            

    def isVisible(self):

        return self._visible

        

    def getContents(self):

        return self._contents       


    def getShortDescription(self):

        return self._short_description


    def getLongDescription(self):

        return self._long_description


    def getSize(self):

        return "Object Details ... Weight: %.2f, Height: %.2f, Width: %.2f, Depth: %.2f" % (self._weight, self._height, self._width, self._depth)


    def getHeight(self):

        return self._height


    def getWeight(self):

        return self._weight


    def getName(self):

        return self._name


    def getObjectId(self):

        return self._object_id


    def getDescription(self):

        output = ''

        vowels = ['a','e','i','o','u']

        if isinstance(self,Place):

            short_desc = self.getShortDescription()

            output += short_desc + "\n"

            underline = ''

            for i in str(short_desc):

                underline += '-'

            output += underline + "\n"

            output += self.getLongDescription() + '\n'

            for thing in self.getContents():

                if isinstance(thing,ExitObject):

                    if thing.isVisible():

                        output += "There is "

                        if thing.getName()[0].lower() in vowels:

                            output += 'an '

                        else:

                            output += 'a '

                        output += thing.getName() + ' '

                        output += 'here.\n'

                    else:

                        ### Don't short exits if they are just cardinal directions (_visible=False)

                        pass


            itemlist = []

            peoplelist = []

            for thing in self.getContents():

                if isinstance(thing,SimObject) and not isinstance(thing,ExitObject) and not isinstance(thing,Person):

                    itemlist.append(thing.getName()) 

                elif isinstance(thing,Person):

                    peoplelist.append(thing.getName())

            if len(itemlist) == 1:

                output += "There is "

                if itemlist[0][0].lower() in vowels:

                    output += 'an '

                else:

                    output += 'a '

                output += itemlist[0] + ' '

                output += 'here.\n'

            if len(itemlist) >= 2:                                    

                total_items = len(itemlist)

                item_counter = 1

                output += "There are "

                for items in itemlist:

                    if items[0].lower() in vowels:

                        output += 'an '

                    else:

                        output += 'a '  

                    if item_counter <= total_items-2:

                        output += str(items)+', '

                    elif item_counter == total_items-1:

                        output += str(items)+' and '

                    else:

                        output += items + " "

                    item_counter += 1

                output += "here.\n"

                output += "\n"

            if len(peoplelist) == 1:

                output += str(peoplelist[0]) + " is here.\n" 

            elif len(peoplelist) > 1:

                item_counter = 1

                total_items = len(peoplelist)

                for items in peoplelist:

                    if item_counter <= total_items-2:

                        output += str(items) + ', '

                    elif item_counter == total_items-1:

                        output += str(items) + ' and '

                    else:

                        output += str(items)

                    item_counter += 1

                output += "are here.\n"  

        elif isinstance(self,Person):

            output += self.getName()

            output += "is standing before you!\n"

        elif isinstance(self,ExitObject):

            if self.isVisible():

                output += str(self.getShortDescription()) + '\n'

            else:

                output += "You see nothing out of the ordinary here.\n"

        else:

            output += "unsure of type!\n"

        output += "\n"

        return output

        

#####################################################

#                              P   L   A   C   E        C   L   A   S   S                                  #

#####################################################


class Place(SimObject):

    def __init__(self,

                object_id = 0,

                object_sku = 0,

                short_description = 'Short Description',

                long_description = 'Long Description',

                name = 'Name',

                weight = 1.0,

                height = 1.0,

                width  = 1.0,

                depth  = 1.0,

                visible = True,

                contents = []):

        SimObject.__init__(self,

                            object_id=object_id,

                            short_description = short_description,

                            long_description  = long_description,

                            name              = name,

                            weight            = weight,

                            height            = height,

                            width             = width,

                            depth             = depth,

                            visible           = visible,

                            object_sku        = object_sku,

                            contents          = [])



#####################################################

#                          P   E   R   S   O   N          C   L   A   S   S                              #

#####################################################


class Person(SimObject):

    def __init__(self,name="",object_id=0,object_sku=0):

        SimObject.__init__(self,name=name,object_id=object_id,object_sku=object_sku)

        self._hp   = 100

    def isAlive(self):

        if self._hp > 0:

            return True

        else:

            return False

    def getStats(self):

        print "%s has %i hit points remaining!" % (self._name,self._hp)

    def receiveHit(self,damage="0"):

        self._hp = self._hp - damage

        if self._hp <>

            self._hp = 0

    def attack(self,enemy):

        if type(enemy) == type(self):

            attempt_roll = randint(1,10)

            if attempt_roll > 5:

                enemy.receiveHit(attempt_roll)         

            else:

                print "Missed %s!" % str(enemy._name)

        else:

            print "Cannot attack %s" % str(enemy)

    def getSize(self):

        return "Person Details ... Weight: %.1f, Height: %.1f, Width: %.1f, Depth: %.1f" % (self._weight, self._height, self._width, self._depth)

    def move(self,destination):

        #### add test against dimensions.  person WxD must be greater than Exit HxW, and the smallest Person dimension much be

        #### smaller than the smallest Exit dimension

        destination_room = self.getObjectById(destination)

        destination_room.addContents(self)


#####################################################

#                                  E   X   I   T        C   L   A   S   S                                    #

#####################################################


class ExitObject(SimObject):

    def __init__(self,visible=False,name="ExitName",short_description='Exit',

long_description='an Exit',aliases=(), destination=0,object_id=0,object_sku=0, weight=1.0,width=1.0,height=1.0,depth=1.0,closed=False):

        """Aliases are lists of names by which this exit can be referenced"""

        SimObject.__init__(self,visible=visible,name=name,short_description= 

short_description, long_description=long_description,object_id=object_id,

object_sku=object_sku, weight=weight,width=width,height=height,depth=depth,

closed=closed)

        self._aliases = aliases

        self._destination = destination

    def getDestination(self):

        return self._destination

    def getAliases(self):

        return self._aliases