Code Refinement

October 11th, 2007
Posted in Refactoring | No Comments

Everyday is an opportunity to learn something new. Today, I learned how to set the tab width for vi (set tabstop=2) while trying to format the picture for this blog entry, for example. Daily learning is a form of personal refinement. Accumulated knowledge allows people to do things better.

If the lesson relates to development, then that piece of incremental personal development can be used to enhance software development.

Here are snippets of code that I have written and currently maintain:
differences.jpg

The functionality of both versions are essentially identical. I wrote the version on the left side approximately two years ago. The one on the right side is the current and evolving version.

Changing the function’s accessibility is a significant evolution of the code. Straying from the simple public/private access control dichotomy, I employ protected accessibility to allow child classes to reuse this code. It is currently labeled final, because I do not want child classes to be able to override this function at this time. I may remove this restriction, if I later feel that there is a need. This follows the computing adages of minimizing interfaces, minimizing code duplication, and employing code reuse. Restrictions on a module’s interface can be relaxed. Restrictions cannot, however, be increased due to possible dependencies. Code may have been implemented to depend on a module’s interface, and to restrict accessibility to a function of the module, for example, would require code to be reworked. The cost of reworking the code that depends on the relaxed interface to use a more restrictive one grows significantly along with the amount of dependent code.

Supporting two versions of a particular class encouraged my use of inheritance here. Two files were used to provide a debug and a production version of the class. Modifying code that is common to both versions required that code be copied from one file to the other. The duplication of code is a “smell,” as Fowler puts it, that indicates the code can be better organized. Instead of replacing the debug and production versions of the files containing a class as I did earlier, which is a potentially dangerous practice, I use inheritance to localize duplicate code into the parent class and employ a factory method (not shown) that returns a debug or production instance of the class. If dependents on this class use the factory method to create an object, they do not have to be aware of which child class an object is. This assumes that the dependent code is written to depend on the interface that is defined by the factory method’s return type, which is usually a parent class. Since an object of the parent class can be substituted with objects of child classes, the factory method can return an instance of the child class while advertising the parent class as its return type to dependent code, and the dependent code will act on the object just the same.

The use of accessors to fetch the field values of a class instance is another significant change in the code. Although this does not serve more than little protection from unintentional instance variable modification (the instance variables could still be accessed directly in the member function), it may be useful if lazy evaluation is employed. So, the use of accessor functions is a good practice. A little indirection seems to always be good.

I also introduced a dependency into the function’s implementation. Rather than use a heretodoc string to represent an XML document, I depend on a class that speaks XML.

My code and designs have certainly improved over the years. To help reinforce and develop of my skills, I continually employ good programming and software engineering practices on the projects that involve me. I also analyze my approach and think about alternatives or ways that it can be made better.

Reinforcing Knowledge while Learning

October 3rd, 2007

I just finished rereading Design Patterns: Elements of Reusable Object-Oriented Software. As a little experiment, I will explore how far I can get with the book’s fundamental design patterns with Python, an object-oriented scripting language that I am trying to pick up.

One of the first design patterns I came across even before reading DP is the Singleton pattern. The basic Singleton pattern creates a single instance for an entire system to use. A system task scheduler or print spool are examples of singletons.

The source code of my implementation of the Singleton pattern in Python is presented here:

# Singleton class definition
class MySingleton ( object ):
  __instance = None	

  def __new__( cname ):
    if not cname.__instance:
      cname.__instance =
        super( MySingleton, cname ).__new__( cname )
    return cname.__instance

  def setX( self, x ):
      self.x = x

  def getX( self ):
      return self.x

# Singleton client code
a = MySingleton()
b = MySingleton()

print a
print b

a.setX("hello")
print b.getX()

The output from the Python interpreter is:

<__main__.MySingleton object at 0xb7ebb24c>
<__main__.MySingleton object at 0xb7ebb24c>
hello

Printing the objects shows that the objects are located at the same address and are the same type. Furthermore, invoking operations that modify the instance that is attached to “a” affects the one that is attached to “b.” Changes to “a” are reflected in “b.” In other words, the instance of MySingleton that is referenced by “a” and “b” are the same. This demonstrates the Singleton pattern in Python.

Goal-based Learning

September 18th, 2007

“You dropped a hundred and fifty grand on a fucking education you could’ve got for a dollar fifty in late charges at the public library.” –Will, Good Will Hunting

My experience in college can be summed up as an ongoing lesson on learning. College was an opportunity to learn how to learn. I am employing tactics, which I used to succeed at a university, to pick up the knowledge that I need to perform tasks and prepare for future accomplishments.

There have been many books that I have read since I left college. Some books that I believe have improved my code and overall software architecture are Object-Oriented Analysis and Design with Applications by Booch et al. and the gang of four’s Design Patterns: Elements of Reusable Object-Oriented Software. These books are not specific to a particular programming environment, but can be applied to many kinds of projects.

As an example of a book that is less theoretical and more applicable, C.J. Date’s An Introduction to Database Systems comes to mind. I have read several books on team and project management, too. I also picked up books that I wanted to read while I was at college, namely, Richard Stevens’ Unix Network Programming. I have also read books on notations like the UML, but I feel the same about reading such books as I did in college. I am still somewhat discouraged from reading about notations that I perceive as more transient than a given widely accepted, general programming language.

Not all books that I have read are technical. I have read books that talk about personal finance and planning, such as Peter Lynch’s Beating the Street and One Up on Wall Street, David and Tom Gardner’s The Motley Fools Rule Breakers Rule Makers and The Motley Fool Investment Guide, along with Robert Kiyosaki’s Rich Dad, Poor Dad.

My reading queue currently includes a math book on game theory, Luce and Raiffa’s Games and Decisions, and one on legal matters with regard to software. I did not care much for reading while I was in school, so I am pretty impressed with the amount of reading that I have done lately. There are still many books on topics that I would like to study and other books that are listed in the syllabuses of graduate level university courses that make up my reading list.

Shall, Should, and May

September 16th, 2007

The text of RFC2119, which describes the use of these phrases in system documentation, is presented here:

Network Working Group
Request for Comments: 2119
BCP: 14
Category: Best Current Practice

S. Bradner
Harvard University
March 1997

— Status of this Memo —
This document specifies an Internet Best Current Practices for the
Internet Community, and requests discussion and suggestions for
improvements. Distribution of this memo is unlimited.

— Abstract —
In many standards track documents several words are used to signify the requirements in the specification. These words are often capitalized. This document defines these words as they should be interpreted in IETF documents. Authors who follow these guidelines should incorporate this phrase near the beginning of their document:

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.

Note that the force of these words is modified by the requirement level of the document in which they are used.

1. MUST — This word, or the terms “REQUIRED” or “SHALL”, mean that the definition is an absolute requirement of the specification.

2. MUST NOT — This phrase, or the phrase “SHALL NOT”, mean that the definition is an absolute prohibition of the specification.

3. SHOULD — This word, or the adjective “RECOMMENDED”, mean that there may exist valid reasons in particular circumstances to ignore a particular item, but the full implications must be understood and carefully weighed before choosing a different course.

4. SHOULD NOT — This phrase, or the phrase “NOT RECOMMENDED” mean that there may exist valid reasons in particular circumstances when the particular behavior is acceptable or even useful, but the full implications should be understood and the case carefully weighed before implementing any behavior described with this label.

5. MAY — This word, or the adjective “OPTIONAL”, mean that an item is truly optional. One vendor may choose to include the item because a particular marketplace requires it or because the vendor feels that it enhances the product while another vendor may omit the same item. An implementation which does not include a particular option MUST be prepared to interoperate with another implementation which does include the option, though perhaps with reduced functionality. In the same vein an implementation which does include a particular option MUST be prepared to interoperate with another implementation which does not include the option (except, of course, for the feature the option provides.)

6. Guidance in the use of these Imperatives
Imperatives of the type defined in this memo must be used with care and sparingly. In particular, they MUST only be used where it is actually required for interoperation or to limit behavior which has potential for causing harm (e.g., limiting retransmisssions) For example, they must not be used to try to impose a particular method on implementors where the method is not required for interoperability.

7. Security Considerations
These terms are frequently used to specify behavior with security implications. The effects on security of not implementing a MUST or SHOULD, or doing something the specification says MUST NOT or SHOULD NOT be done may be very subtle. Document authors should take the time to elaborate the security implications of not following recommendations or requirements as most implementors will not have had the benefit of the experience and discussion that produced the specification.

8. Acknowledgments
The definitions of these terms are an amalgam of definitions taken from a number of RFCs. In addition, suggestions have been incorporated from a number of people including Robert Ullmann, Thomas Narten, Neal McBurnett, and Robert Elz.

9. Author’s Address
Scott Bradner
Harvard University
1350 Mass. Ave.
Cambridge, MA 02138
phone – +1 617 495 3864
email – sob@harvard.edu

Secure Coding: Principles & Practices

August 28th, 2007

31a4xgqm9dl_aa_sl160_.jpgI read Graff and van Wyk’s Secure Coding: Principles & Practices to completion, but not because each page was more enlightening than the previous. I realized that the same themes and adages were being repeated constantly after having read half the book. Because it was pretty easy to get midway through the book, I decided on continuing through it for the sake of completeness. As critical as I can be about the book, there are characteristics of the book that may be redeeming.

The lessons that the authors attempt to convey seem to be an extension of what is taught in a typical software engineering course. Being about security, the book suggests that software engineers keep security concerns in mind while proceeding through a development life cycle. While testing and designing, the book suggests without going into specifics, software engineers should think about ways that other entities may try to subvert their application systems. The authors encourage implementing systems with a high degree of visibility, accountability, and traceability. They also stress the need to consider the security of an application’s target environment. Normal review of the a and testing of an implementation during a software development life cycle should already address security concerns. The book serves to make this point explicit.

The authors’ principal ideas are repeated throughout the book. Perhaps, the authors believe that people retain about 10% on average of the information that comes to them, and the authors feel they need to repeat their lesson at least ten times to guarantee its reception. The book should not be discounted as a waste of time. After all, the stories, other than the same SYN flood and buffer overrun examples that are used throughout the book, were fairly entertaining.