HomePractices Page 4 - The Art Of Software Development (part 3): Coding To A Plan
Batteries Not Included - Practices
With the design out of the way, it's time to finally sit downand write some code. This article discusses the implementation phase ofthe software cycle, outlining some ideas and techniques that should helpyou deliver cleaner, faster and more maintainable code. Miss it at yourperil!
In order to increase the portability and maintainability of a Web application, consider making the following components standard inclusions in every project you develop.
1. An interface abstraction layer: By substituting variable "placeholders" for actual content in an HTML page, tag-based scripting languages like PHP, Perl and JSP make it easy to construct dynamic Web pages; simply alter the values of the variables embedded within the HTML code, and the content displayed on the page changes appropriately.
This convenience comes at a price - most of these scripts are so closely interwoven with HTML code that maintaining them is a nightmare. Since both the HTML user interface elements and the program logic are in the same physical file, it becomes difficult for users with no programming experience to modify one without affecting the other. And having a developer hand-hold an interface designer through the development process is expensive to the organization as a whole, in terms of both time and money.
Consequently, one of the most important things you can do when implementing a Web application is separate the user interface from the business logic. This is typically done via a template engine, which works by abstracting interface elements into independent templates, text files typically containing both static elements (HTML code, ASCII text) and template variables, and providing developers with an API to link templates together, and to fill them with data. When a template engine reads a template file, it automatically replaces the variables within it with their values; these values may be defined by the developer at run-time, may be read from another file, or may be extracted from a database.
Since templates may be nested or inherited, a template engine also adds reusability to your Web application (a template can be used again and again, even across different projects) and makes it easier to localize the impact of a change.
A number of template engines exist to help you accomplish this separation - FastTemplate, patTemplate and Smarty (PHP), CGI::FastTemplate (Perl), Cheetah (Python) and Velocity (JSP) are some of the more common ones.
2. A database abstraction layer: If you've worked with different databases, you've probably seen that each database operates in a slightly different manner from the others. The data types aren't always uniform, and many of them come with proprietary extensions (transactions, stored procedures et al) that aren't supported elsewhere. Additionally, in some programming languages, the API to interact with these databases is not always uniform; you may need to change specific function calls in your code as your RDBMS changes.
For all these reasons, switching from one database to another is typically a complex process, one which usually involves porting data from one system to another (with the assorted datatyping complications), rewriting your code to use a new database API, and testing it to make sure it all works. And that's where a database abstraction layer can help.
Typically, a database abstraction layer functions as a wrapper around your code, exposing a set of generic methods to interact with a database server. These generic methods are internally mapped to the native API for each corresponding database, with the abstraction layer taking care of ensuring that the correct method is called for your selected database type. Additionally, most abstraction layers also incorporate a generic superset of datatypes, which get internally converted into datatypes native to the selected RDBMS. This increases the portability of your application, and also helps you keep things simple over the long term.
A number of different database abstraction layers exist to help you accomplish this: DBI (Perl), Metabase and ADODB (PHP), and JDBC (Java).
3. An exception handler: No developer, no matter how good (s)he is, writes bug-free code all the time. Consequently, most programming languages come with built-in capabilities to catch errors and take remedial action. Typically, this action involves displaying a warning message and - depending on the severity of the error - terminating program execution.
Now, the error messages displayed by most programming languages tend to be both cryptic and overly technical in the information they provide. While this behaviour is acceptable during the early implementation phase of a software project, it cannot continue indefinitely; it is generally considered more professional to intercept these errors and either resolve them, if resolution is possible, or notify the user with a clear error message, if not.
It's therefore a good idea to include a generic exception handler in your application, one that is capable of tracking and handling the different types of errors that may occur during program execution. Typically, this exception handler is a layer over and above the rudimentary error-handling functions provided by the programming language, and it allows you to define custom error types, catch errors as they occur, control the display of the subsequent error messages, and optionally log error messages in a custom report format.