Border
Author: Bruce Grant, Jr. (BX)
Published: March 13, 2009
Adding Discipline to Scripting Languages
The power, flexibility and development velocity of modern scripting languages makes them attractive to software engineering managers everywhere. If your project only lives a few years then very little if any discipline is really needed. However, if your product is successful and you have not instituted sound engineering practices from the get-go you may find yourself in a world of hurt with code that is brittle, difficult to maintain and that actually impedes your ability to make quick changes. This article provides a few simple tips based on my experience creating two large, enterprise-scale systems using two very different scripting languages: JavaScript and Lua.
I didn't cut my teeth on scripting languages right out of college like the current generation. I started with highly structured, compile-time checked languages such as Pascal, C++ and Java. About six years into my career, however, I found myself creating a product with a few hundred thousand lines of JavaScript in it. The product was called WebFace for a company named Vultus.

In 2000 I helped pioneer one of the first commercial AJAX environments. We created a graphical windowing environment in the browser using JavaScript that allowed a developer to create XML markup that in the browser was instantiated as a series of buttons, text fields, data sources, dropdowns, modal windows, etc. It was pretty awesome.

As we went around the country seeking investment capital and pitched big companies such as IBM and others we continually met with skepticism that anyone could create a robust application platform in JavaScript. Remember, this was well before Google blessed DHTML with its Gmail application. By applying the necessary discipline to the problem at hand we succeeded in creating a robust, sophisticated application platform in JavaScript.

Well, its almost ten years later and many have embraced scripting languages including PHP, Python and the like and had a lot of success with them. However, there is a tendency in many of these projects that use scripting languages to think that the power and flexibility of the scripting language obviate the need for sound engineering practices. Nothing could be further from the truth. So, if you're an engineering manager and you care about cost-of-ownership, maintainability and your job later on when success hits, read on.

  1. Create Structure
    Most scripting languages provide the putty from which you can do almost anything. Some have some pre-defined ways to achieve Object-oriented behavior. Research the way that best fits your project and standardize on it. In fact, go further. Create your own class creation methods that you can parse for and document to generate your documentation (more later). Also, figure out how you're going to organize your source tree. Separate your source code from your unit tests. If you're going to have native C++ code in your project, separate it and its unit tests out also.

    You need to spell this structure out from the very beginning and enforce adherence by all on the project or you'll wind up with many differing approaches to the same problems. This will eventually lead to subtle differences in behavior, added complexity and inflexibility. Lets say some day you want to carte-blanch change how you're achieving inheritance. By creating your own wrapper functionality you have one place you can make the change. Otherwise, what would have been simple is now very, very time consuming.
  2. Generate API Docs
    You must enforce strict documentation standards so that every package/module/file and every class/function/instance member are given a document header. Since it's so easy to crank out script the very act of documenting will help engineers pause to think about where the code should go. Then, use whatever tool is handy for your scripting language to generate JavaDoc style (or whatever flavor) documentation from your own source code.

    This will help protect the mind share of what you've created making it easier in the future to keep a holistic view of what the code does. You never know where things will take your project. You may someday need to make radical changes or integrate with another product and this documentation will save you an enormous effort. The documentation will also help you train newbies as you gain success and you'll be able to ramp resources onto the project more quickly.
  3. Enforce Datatype Checking
    Some of you will think I'm old school and wonder why I'd even choose a scripting language when I say that you must add data types to the scripting language. Let me clarify what I mean here. On the WebFace product we adopted the JavaDoc style of documenting source code. Then we wrote our own parser for that documentation. Then we added some taglets into the documentation headers of functions that described the expected parameter types and return types.

    In JavaScript we used a well-known practice of "mix-ins" to get Object-Oriented like behavior. In the documentation header of our classes we specified what classes we inherited from. Then, our documentation included the contracts of functions and our class inheritance hierarchy. This saved us enormous amounts of time debugging code we'd left behind long ago.

    On the more recent Lua scripting language project we've gone even further to create an inference-based type-checking system based on these documentation taglets. The product we're creating in Lua has to be absolutely rock solid and any branch of code not unit tested is a potential uncaught exception waiting to blow up our application since there are no compile-time checks on that code. Well, we want the development velocity gained by using a scripting language but we needed a little more confidence in our code.

    So, we used tools like Lemon and Antlr to get a parse tree of the code and do some basic type checking to ensure we weren't accidentally trying to dereference a string as a complex object which would cause an uncaught exception. We have excellent unit test coverage (around 85+%) but still that leaves many branches as unknowns.
  4. Automate Everything
    Automation is your friend. It's tough to pay the price to do the automation but trust me it will pay out ten-fold later. Automate your build process. Automate the enforcement of your documentation and other standards when developers check in code. Automate the execution of your unit tests and your functional tests. Automate deployment. Through all of this include simple email feedback loops to know that it all worked. If you want to spend more time at it you can integrate the process into a tool like Jira or Confluence.
  5. Unit Test
    If you're not sold on unit testing it's well past time to repent. There's a panoply of documentation on the subject. Go read it and convert yourself. Then convert your team. Unit testing is even more important in languages without compile-time checks. Unit testing will save you time not take more of it.
Comments
Be the first to add a comment.
Add a Comment
User:
Anonymous (Login or Create Account or Help)
Border