Several weeks ago I was out of town teaching an on-site custom training course. While I don’t like being away from my wife and six children, I always enjoy the opportunity to teach Python and demonstrate the productivity that can be gained with the tools that are available for it (e.g. NumPy, SciPy, Matplotlib, Chaco, Traits, Mayavi, nose, pyflakes, sympy, IPython, …). We typically teach scientists and engineers, so our students are often well-versed in topics such as vectorization, linear algebra, and signal/image processing. We also train professional programmers, however, and with that audience the aforementioned ideas might be less familiar territory. Such was the case with last month’s class, with mostly developers in attendance. This type of student, of course, brings an entirely different type of expertise to the classroom. I really enjoy this shift in context and appreciate the opportunity to discuss software engineering concepts like object-oriented programming.
Now, I don’t consider myself a computer science expert. When I’m discussing probability theory, electromagnetics, magnetic resonance imaging, ultrasound, or inverse theory subjects in which I’ve read enough literature and considered the prominent problems thoroughly enough to provide some depth to my perspective the conversation will turn a bit more academic. My understanding of programming, however, is more pragmatic and based on experience rather than theory.
It’s a bit ironic actually. In academia, I was much more of a theoretician than an experimentalist. I was known for giving very hard tests in subject areas that most students hated (and I loved). In the business world, the reverse seems to be true, as my understanding comes mostly from experiment and experience. My knowledge of software engineering has been gleaned from hands-on development and observation, with reinforcement and guidance provided by a handful of wonderful books such as “The Pragmatic Programmer” by Andrew Hunt and David Thomas.
It’s also important to recognize the impact that interaction with the Python community has had on my growth as a software developer. Reading the source code of both Python and Numeric, creating PEPS, writing NumPy, and reviewing patches have all been helpful in my ongoing struggle to produce useful contributions. Finally, being a part of the Enthought development team and watching how our software craftsmen deconstruct scientific problems so that they can create elegant solutions with code has dramatically informed my capacity to think like a scientist and developer simultaneously.
One of the things I’ve always appreciated about Python is the ability to program in many styles: object-oriented, procedural, functional, etc. While some languages immerse you in object-oriented programming, Python is less pushy, allowing you to use it as necessary and embellish it with additional styles. Perhaps, this is why I enjoy writing code with Python so much. My first exposure to real programming (beyond a few lines of Basic or toy assembly code on my TI 99/4A) was in high school where I learned Pascal. The book that I learned from taught me about top-down development: think of the problem at a large scale, break it up into smaller, logical pieces, successively code those pieces repeating the pattern until you are down to the smallest segments that you can see how to convert to code. This approach naturally lends itself to procedural programming.
While learning engineering in school, these concepts were reinforced as I learned how complex systems can be built by breaking the large system down into its component parts, designing and testing those parts, and then connecting them together into the larger system. In this process, each component may also be in fact another complex system that requires the same kind of design approach. In my mind, this process of creating robust components that are separately testable and interact through specific interfaces is the key to building robust products. It is encouraging that these concepts are also emerging in the computer software world in ideas like component-oriented programming, or Component-based Software Engineering.
Speaking of components… one of the fun things that happened every year while I was teaching Electrical Engineering at BYU is that I would get in my mail box several huge catalogs of electronic parts. These catalogs would contain thousands and thousands of parts. Even though I knew just enough about hardware to be dangerous, I was enthralled by the catalogs and would flip through them and try to imagine what could be built with all those cool components. MCM Electronics and Texas Instruments were two favorite vendors whose offerings I would meander through, idly dreaming what could be built if I had more hardware talent.
Then, as a passive student of economics, I learned from Gene Callahan this great concept called the structure of capital (this is not to be confused with the corporate finance concept of “capital structure”). This concept tries to capture all the necessary building blocks (and machinery necessary for their creation) that go in to producing even the most ordinary consumer good. This interlocking structure is critical to the creation of everything we buy. A valuable introduction to the big picture of this idea is the classic (if somewhat out-dated) essay “I Pencil”, by Leonard Reed.
It seems that the progress of any human-built thought, tool, organization, and society is restricted by the limited short-term memory and information management capabilities of the human brain. But, fortunately, the human brain is also the source of our escape from the brash consequences of these limitations. We each have the creative capacity, the generative capacity, and the power to build abstractions and ideas. As described in the last link, this is the capacity that education should be striving to enhance.
When developing software, we are limited by time and human understanding to the abstractions available to us. Computer science has steadily evolved abstractions that make a difference: integers, floating point numbers, data structures, file-systems, network protocols, and on and on. The good abstractions make subsequent programming easier and more capable. Some abstractions, however, are not widely applicable and never achieve that type of longevity. In fact, one of the struggles I have with a focus on object-oriented programming is that it turns everybody’s half-baked abstractions into objects that now must be dealt with by future developers. And shared-abstractions are a critical part of progress in any social endeavor.
A brain with a warehouse of intertwined abstractions has the ability to create more sophisticated, more compelling, more beautiful, and ever more useful things. In the same way, an economy with a network of intertwined capital structure has the ability to provide more satisfaction more quickly for its diverse participants. Analogies to this concept can probably be made in any creative enterprise: mathematics, music, literature, and science. Of more immediate interest to my day-to-day activities, however, is that developers with a cornucopia of intertwined abstractions can create ever more compelling, beautiful, and useful applications that will continue to drive our infatuation with computing machines. Python makes it easy to become a part of that continuing creation.