507 lines
12 KiB
HTML
507 lines
12 KiB
HTML
<!--startcut ==============================================-->
|
|
<!-- *** BEGIN HTML header *** -->
|
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
|
<HTML><HEAD>
|
|
<title>Creating Reusable Software Libraries LG #81</title>
|
|
</HEAD>
|
|
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#0000AF"
|
|
ALINK="#FF0000">
|
|
<!-- *** END HTML header *** -->
|
|
|
|
<CENTER>
|
|
<A HREF="http://www.linuxgazette.com/">
|
|
<IMG ALT="LINUX GAZETTE" SRC="../gx/lglogo.png"
|
|
WIDTH="600" HEIGHT="124" border="0"></A>
|
|
<BR>
|
|
|
|
<!-- *** BEGIN navbar *** -->
|
|
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="sevenich.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="index.html"><IMG ALT="[ Table of Contents ]" SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../index.html"><IMG ALT="[ Front Page ]" SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue81/tougher.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../lg_faq.html"><IMG ALT="[ FAQ ]" SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="vikas.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
|
|
<!-- *** END navbar *** -->
|
|
<P>
|
|
</CENTER>
|
|
|
|
<!--endcut ============================================================-->
|
|
|
|
<H4 ALIGN="center">
|
|
"Linux Gazette...<I>making Linux just a little more fun!</I>"
|
|
</H4>
|
|
|
|
<P> <HR> <P>
|
|
<!--===================================================================-->
|
|
|
|
<center>
|
|
<H1><font color="maroon">Creating Reusable Software Libraries</font></H1>
|
|
<H4>By <a href="mailto:robt@robtougher.com">Rob Tougher</a></H4>
|
|
</center>
|
|
<P> <HR> <P>
|
|
|
|
<!-- END header -->
|
|
|
|
|
|
|
|
|
|
<dl>
|
|
<dt><a href=#1>1. Introduction</a>
|
|
<dt><a href=#2>2. Making It Easy To Use</a>
|
|
<dd><a href=#2.1>2.1 Keeping It Simple</a>
|
|
<dd><a href=#2.2>2.2 Being Consistent</a>
|
|
<dd><a href=#2.3>2.3 Making It Intuitive</a>
|
|
<dt><a href=#3>3. Testing Thoroughly</a>
|
|
<dt><a href=#4>4. Providing Detailed Error Information</a>
|
|
<dt><a href=#5>5. Conclusion</a>
|
|
</dl>
|
|
|
|
|
|
<a name=1></a>
|
|
<h3>1. Introduction</h3>
|
|
|
|
<p>
|
|
Software libraries provide functionality to
|
|
application developers. They consist of reusable code that
|
|
developers can utilize in their projects.
|
|
Software libraries targeted for Linux are usually available in both
|
|
binary and source code form.
|
|
</p>
|
|
|
|
|
|
<p>
|
|
A well-written software library:
|
|
</p>
|
|
|
|
<ul>
|
|
<li>is easy to use
|
|
<li>works flawlessly
|
|
<li>provides detailed error information
|
|
</ul>
|
|
|
|
<p>
|
|
This article describes the above principles of library creation,
|
|
and gives examples in C++.
|
|
</p>
|
|
|
|
<table width=80% border=1>
|
|
<tr>
|
|
<td bgcolor=#EEEEEE>
|
|
<font>
|
|
|
|
<h4>
|
|
Is This Article For You?
|
|
</h4>
|
|
|
|
<p>
|
|
Create software libraries only when you have to.
|
|
Ask yourself
|
|
these questions before proceeding:
|
|
</p>
|
|
|
|
|
|
<ul>
|
|
<li><i>Will anyone (including you) need functionality X in future applications?</i>
|
|
<li><i>If so, does a library implementing functionality X already exist?</i>
|
|
</ul>
|
|
|
|
|
|
<p>
|
|
If no one will need the functionality you are developing,
|
|
or a software library implementing it already exists,
|
|
don't create a new library.
|
|
</p>
|
|
|
|
</font>
|
|
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
|
|
<a name=2></a>
|
|
<h3>2. Making It Easy To Use</h3>
|
|
|
|
<p>
|
|
The first step in creating a software library is designing
|
|
its <b>interface</b>.
|
|
|
|
Interfaces written in procedural languages, like C, contain
|
|
functions. Interfaces written in object-oriented languages,
|
|
like C++ and Python, can contain both functions and classes.
|
|
</p>
|
|
|
|
<p>
|
|
Remember this motto when designing your interface:
|
|
</p>
|
|
|
|
<ul>
|
|
<li><i>The easier to use, the better</i>
|
|
</ul>
|
|
|
|
<p>
|
|
As a library designer, I am constantly faced with
|
|
finding the right balance between functionality and
|
|
ease of use. The above motto helps me resist
|
|
adding too much functionality into my designs.
|
|
</p>
|
|
|
|
<p>
|
|
Stick with the following guidelines, and you'll be fine.
|
|
</p>
|
|
|
|
|
|
<a name=2.1></a>
|
|
<h4>2.1 Keeping It Simple</h4>
|
|
|
|
|
|
<p>
|
|
The more complex a library, the harder it
|
|
is to use.
|
|
</p>
|
|
|
|
<ul>
|
|
<li><i>Keep It Simple, Stupid</i>
|
|
</ul>
|
|
|
|
<p>
|
|
I recently encountered a C++ library that consisted of
|
|
one class. This class contained 150 methods.
|
|
<i>150 methods!</i>
|
|
The designer was most likely a C veteran using C++ - the
|
|
class acted like a C module.
|
|
Because this class was so complex, it was
|
|
<i>very difficult</i> to learn.
|
|
</p>
|
|
|
|
|
|
<p>
|
|
Avoid complexity in your designs, and your interfaces will
|
|
be cleaner and easier to understand.
|
|
</p>
|
|
|
|
|
|
<a name=2.2></a>
|
|
<h4>2.2 Being Consistent</h4>
|
|
|
|
<p>
|
|
Users learn consistent interfaces more easily. After learning
|
|
the rules once, they feel confident in applying those
|
|
rules across all classes and methods, even if they
|
|
haven't used those classes and methods before.
|
|
</p>
|
|
|
|
|
|
|
|
<p>
|
|
One example I am guilty of involves public accessors
|
|
for private variables. I sometimes do the following:
|
|
</p>
|
|
|
|
<pre>
|
|
class point
|
|
{
|
|
public:
|
|
int get_x() { return m_x; }
|
|
int set_x ( int x ) { m_x = x; }
|
|
|
|
int y() { return m_y; }
|
|
|
|
private:
|
|
int m_x, m_y;
|
|
};
|
|
</pre>
|
|
|
|
<p>
|
|
Do you see the problem here? For the m_x member, the public accessor
|
|
is "get_x()", but for the m_y member, the public accessor is
|
|
"y()". This inconsistency generates more work for the users - they
|
|
have to look up the definition of each accessor before using it.
|
|
</p>
|
|
|
|
|
|
<p>
|
|
Here's another example of an inconsistent interface:
|
|
</p>
|
|
|
|
<pre>
|
|
class DataBase
|
|
{
|
|
public:
|
|
|
|
recordset get_recordset ( const std::string sql );
|
|
void RunSQLQuery ( std::string query, std::string connection );
|
|
|
|
std::string connectionString() { return m_connection_string; }
|
|
|
|
long m_sError;
|
|
|
|
private:
|
|
|
|
std::string m_connection_string;
|
|
};
|
|
</pre>
|
|
|
|
|
|
<p>
|
|
Can you spot its problems? I can think of at least
|
|
these items:
|
|
</p>
|
|
|
|
<ul>
|
|
<li>Methods and variables are not named consistently
|
|
<li>Two different terms, <i>sql</i> and <i>query</i>, are
|
|
used to denote a SQL string
|
|
<li><i>m_sError</i> does not have a public accessor
|
|
<li><i>get_recordset()</i> does not have a <i>connection</i> in
|
|
its argument list
|
|
</ul>
|
|
|
|
<p>
|
|
Here is a revised version that solves these problems:
|
|
</p>
|
|
|
|
<pre>
|
|
class database
|
|
{
|
|
public:
|
|
|
|
recordset get_recordset ( const std::string sql );
|
|
void run_sql_query ( std::string sql );
|
|
|
|
std::string connection_string() { return m_connection_string; }
|
|
long error() { return m_error; }
|
|
|
|
private:
|
|
|
|
std::string m_connection_string;
|
|
long m_error;
|
|
};
|
|
</pre>
|
|
|
|
|
|
<p>
|
|
Keep your interfaces as consistent as possible - your users will
|
|
find them much easier to learn.
|
|
</p>
|
|
|
|
|
|
|
|
<a name=2.3></a>
|
|
<h4>2.3 Making It Intuitive</h4>
|
|
|
|
<p>
|
|
Design an interface how you would expect it to
|
|
work from a user's point of view - don't design it
|
|
with the internal implementation in mind.
|
|
</p>
|
|
|
|
<p>
|
|
I find that the easiest way to design an intuitive interface
|
|
is to write code that will use the library <i>before</i> actually
|
|
writing the library. This forces me to think about the
|
|
library from the user's standpoint.
|
|
</p>
|
|
|
|
<p>
|
|
Let's look at an example. I was recently considering writing
|
|
an encryption library based
|
|
on OpenSSL. Before thinking about the library
|
|
design, I wrote some code snippets:
|
|
</p>
|
|
|
|
<pre>
|
|
crypto::message msg ( "My data" );
|
|
crypto::key k ( "my key" );
|
|
|
|
// blowfish algorithm
|
|
msg.encrypt ( k, crypto::blowfish );
|
|
msg.decrypt ( k, crypto::blowfish ):
|
|
|
|
// rijndael algorithm
|
|
msg.encrypt ( k, crypto::rijndael );
|
|
msg.decrypt ( k, crypto::rijndael ):
|
|
</pre>
|
|
|
|
|
|
|
|
<p>
|
|
This code helped me think about how I should design the interface -
|
|
it put me in the user's shoes. If I decide to implement this
|
|
library, my design will flow from these initial ideas.
|
|
</p>
|
|
|
|
|
|
|
|
<a name=3></a>
|
|
<h3>3. Testing Thoroughly</h3>
|
|
|
|
|
|
<p>
|
|
A software library should work flawlessly. Well not
|
|
<i>flawlessly</i>, but as close to flawless as possible.
|
|
Users of a library need to know that the library is performing
|
|
its tasks correctly.
|
|
</p>
|
|
|
|
<ul>
|
|
<li><i>Why use a software library if it doesn't work correctly?</i>
|
|
</ul>
|
|
|
|
<p>
|
|
I test my software libraries using automated scripts.
|
|
For each library, I create a corresponding
|
|
application that exercises all features of the library.
|
|
</p>
|
|
|
|
<p>
|
|
For example, say I decided to develop the encryption
|
|
library I introduced in the previous section. My test
|
|
application would look like the following:
|
|
</p>
|
|
|
|
|
|
<pre>
|
|
#include "crypto.hpp"
|
|
|
|
int main ( int argc, int argv[] )
|
|
{
|
|
//
|
|
// 1. Encrypt, decrypt, and check
|
|
// message data.
|
|
//
|
|
crypto::message msg ( "Hello there" );
|
|
crypto::key k ( "my key" );
|
|
|
|
msg.encrypt ( k, crypto::blowfish );
|
|
msg.decrypt ( k, crypto::blowfish );
|
|
|
|
if ( msg.data() != "Hello there" )
|
|
{
|
|
// Error!
|
|
}
|
|
|
|
//
|
|
// 2. Encrypt with one algorithm,
|
|
// decrypt with another, and check
|
|
// message data.
|
|
//
|
|
|
|
// etc....
|
|
}
|
|
</pre>
|
|
|
|
|
|
<p>
|
|
I would occasionally run this application to make
|
|
sure that my software library did not have any major
|
|
errors.
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<a name=4></a>
|
|
<h3>4. Providing Detailed Error Information</h3>
|
|
|
|
<p>
|
|
Users need to know when a software library cannot perform
|
|
its tasks correctly.
|
|
</p>
|
|
|
|
<ul>
|
|
<li><i>Alert the user when there is a problem</i>
|
|
</ul>
|
|
|
|
<p>
|
|
Software libraries written in C++ use
|
|
<b>exceptions</b> to pass information to its
|
|
users. Consider the following example:
|
|
</p>
|
|
|
|
|
|
<pre>
|
|
#include <string>
|
|
#include <iostream>
|
|
|
|
|
|
class car
|
|
{
|
|
public:
|
|
void accelerate() { throw error ( "Could not accelerate" ); }
|
|
};
|
|
|
|
|
|
class error
|
|
{
|
|
public:
|
|
Error ( std::string text ) : m_text ( text ) {}
|
|
std::string text() { return m_text; }
|
|
private:
|
|
std::string m_text;
|
|
};
|
|
|
|
|
|
int main ( int argc, int argv[] )
|
|
{
|
|
car my_car;
|
|
|
|
try
|
|
{
|
|
my_car.accelerate();
|
|
}
|
|
catch ( error& e )
|
|
{
|
|
std::cout << e.text() << "\n";
|
|
}
|
|
}
|
|
</pre>
|
|
|
|
|
|
<p>
|
|
The <i>car</i> class uses the <b>throw</b> keyword to
|
|
alert the caller to an erroneous situation. The caller
|
|
catches this exception with the <b>try</b> and
|
|
<b>catch</b> keywords, and deals with the problem.
|
|
</p>
|
|
|
|
<p>
|
|
|
|
</p>
|
|
|
|
<a name=5></a>
|
|
<h3>5. Conclusion</h3>
|
|
|
|
<p>
|
|
In this article I explained the important principles
|
|
of well-written software libraries.
|
|
Hopefully I've explained everything clearly enough so
|
|
that you can incorporate these principles into your
|
|
own libraries.
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<!-- *** BEGIN bio *** -->
|
|
<SPACER TYPE="vertical" SIZE="30">
|
|
<P>
|
|
<H4><IMG ALIGN=BOTTOM ALT="" SRC="../gx/note.gif">Rob Tougher</H4>
|
|
<EM>Rob is a C++ software engineer in the New York City area.</EM>
|
|
|
|
<!-- *** END bio *** -->
|
|
|
|
<!-- *** BEGIN copyright *** -->
|
|
<P> <hr> <!-- P -->
|
|
<H5 ALIGN=center>
|
|
|
|
Copyright © 2002, Rob Tougher.<BR>
|
|
Copying license <A HREF="../copying.html">http://www.linuxgazette.com/copying.html</A><BR>
|
|
Published in Issue 81 of <i>Linux Gazette</i>, August 2002</H5>
|
|
<!-- *** END copyright *** -->
|
|
|
|
<!--startcut ==========================================================-->
|
|
<HR><P>
|
|
<CENTER>
|
|
<!-- *** BEGIN navbar *** -->
|
|
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="sevenich.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="index.html"><IMG ALT="[ Table of Contents ]" SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../index.html"><IMG ALT="[ Front Page ]" SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue81/tougher.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../lg_faq.html"><IMG ALT="[ FAQ ]" SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="vikas.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
|
|
<!-- *** END navbar *** -->
|
|
</CENTER>
|
|
</BODY></HTML>
|
|
<!--endcut ============================================================-->
|