📄 ch16_01.htm
字号:
<a name="ch16-6-fm2xml" /><div class="sect2"><h3 class="sect2">16.1.6. Separating Storage from Your Primary Code</h3><p>The manner of <a name="INDEX-3137" /> <a name="INDEX-3138" /> <a name="INDEX-3139" />storing and retrieving data isa key architecture decision that every application encounters. Asimple shopping cart might start out using flat text files to storeshopping cart data throughout the user's shopping experience.However, a more sophisticated one will probably want to takeadvantage of relational databases such as MySQL or Oracle. Otherapplications may use DBM hash files.</p><p>Separating the code that is responsible for data storage from yourcore program logic is good architectural design. In practice, thiscan be more difficult to achieve than separating other components ofyour programs such as display. Often your logic is closely tied toyour data. Sometimes you must also make trade-offs with performance;SQL for example is such an expressive language, it is possible toembed logic into your queries, and this is typically much faster andmore memory efficient than duplicating this functionality in yourprograms.</p><p>However, it is a good idea to strive towards a separation, especiallyif your application is using simpler storage mechanisms such as textfiles. Because applications grow, you may easily find yourselfadopting a full RDBMS down the road. The least amount of changerequired in your code, the better.</p><p>One strategy is to simply allow <a name="INDEX-3140" />DBI to be your layer of abstraction. Ifyou are not ready for a database, you can use<a name="INDEX-3141" /><a name="INDEX-3142" /><a name="INDEX-3143" />DBD::CSV to store your data in text files.Later, if you move to a relational database, most of your code thatis built around DBI will not need to change. Keep in mind that notall DBI drivers are equal. DBD::CSV, for example, only supportslimited <a name="INDEX-3144" />SQLqueries; while on the other extreme, complex drivers like<a name="INDEX-3145" /><a name="INDEX-3146" /><a name="INDEX-3147" /> <a name="INDEX-3148" />DBD::Oracle allow you to use storedprocedures written in Oracle's PL/SQL programming language.Thus, even with DBI, you must balance the portability of writingsimple, vanilla SQL against the performance advantages that you canget by taking advantage of particular features available to you withyour current storage mechanism, as well as the likelihood that youwill want to change storage mechanisms in the future.</p></div><a name="ch16-7-fm2xml" /><div class="sect2"><h3 class="sect2">16.1.7. Number of Scripts per Application</h3><p>CGI <a name="INDEX-3149" /> <a name="INDEX-3150" />applications often consist of manydifferent tasks that must work together. For example, in a basiconline store you will have code to display a product catalog, code toupdate a shopping cart, code to display the shopping cart, and codeto accept and process payment information. Some CGI developers wouldargue that all of this should be managed by a single CGI script,possibly breaking some functionality out into modules that can becalled by this script. Others would argue that a separate CGI scriptsshould support each page or functional group of pages, possiblymoving common code into modules that can be shared by this script.There are reasons for pursuing either approach; let's take alook at them.</p><a name="ch16-8-fm2xml" /><div class="sect3"><h3 class="sect3">16.1.7.1. Using one CGI program rather than many for each major application</h3><p>Having one file makes things simple; there is only one file one mustedit to make changes. One doesn't need to look through multiplefiles in order to find a particular section of code. Imagine you sawa directory with multiple applications:</p><blockquote><pre class="code">web_store.cgiorder.cgidisplay_cart.cgimaintain_cart.cgi</pre></blockquote><p>Without delving into the source code, you might pick out that<em class="filename">web_store.cgi</em> is the primary application.Furthermore, you might conclude that the program probably prints outa front page inviting the user to shop and provides links to theother CGI programs. You would also be able to tell which scripts haveto do with ordering, displaying, and maintaining cart information.</p><p>However, without actually going into the source code of all these CGIscripts, it is difficult to tell how they relate to one another. Forexample, can you add or delete shopping cart items from the orderpage?</p><p>Instead, you can make just one CGI program:<em class="filename">web_store.cgi</em>. This combined script can thenimport the functionality of order forms, cart data display andmaintenance using libraries or modules.</p><p>Second, different components often need to share code. It is muchsimpler for one component to access code in another component if theyare in the same file. Moving shared code into modules is certainly analternative that works well for applications distributed intomultiple CGI scripts. However, using modules to share common coderequires a greater degree of planning to know what code can be sharedand what code will not. A single file is more amenable to makingsimple changes.</p><p>It is possible to use modules with this single CGI program approach.In fact, you can keep file sizes small if you want by making theprimary CGI script a basic interface, or a wrapper, that routesrequests to other modules. In this scenario, you create multiplemodules that handle the different tasks. In many ways it is likehaving multiple files except that all HTTP requests are directedthrough a common front-end.</p><p>If you write CGI scripts that you distribute so that others maydownload and install them on their own systems, then you maycertainly want to reduce the number of files in your application. Inthis scenario, the focus is on making the application easy to installand configure. People installing software care more about what thepackage does than one individual tasks are handled by whichcomponent, and it is easier for them to avoid accidentally deleting afile they didn't realize was important if the number of filesis minimized.</p><p>The final reason you may wish to combine CGI scripts is if you arerunning FastCGI. FastCGI runs a separate process for each of your CGIscripts, so the fewer scripts you have, the fewer separate processesare running.</p></div><a name="ch16-9-fm2xml" /><div class="sect3"><h3 class="sect3">16.1.7.2. Using multiple CGI scripts for each major application</h3><p>There are also several reasons to keep applications distributed.First of all, it does keep files smaller and more manageable. Thisalso helps with projects that have multiple developers, becausereconciling changes made by multiple developers working on the samefile at the same time can be complicated to say the least.</p><p>Of course, as we stated before, one can keep files small andseparated when using the single CGI program approach by shifting codeinto modules and restricting the single CGI program to being a simpleinterface that routes requests to the appropriate modules. However,creating a general front-end that uses modules for specific tasks isa rather backward approach for Perl. Typically, Perl modules containgeneral code that can be shared across multiple programs that dospecific tasks. Keeping general code within modules also allows themto be potentially shared across different CGI applications.</p><p>It is true that creating multiple files requires more architecturalplanning when different components need to share the same codebecause the common code must be placed in a module. You should alwaysplan your architecture carefully and be wary of quick and simplesolutions. The problem with quick and simple solutions is that toomany of them begin to bloat an application and create an inferioroverall solution. It may require a bit more work in the short term toshift code in one component into a module because another componentneeds to access it; however, in the long run the application may bemuch more flexible and easier to maintain with this module than itwould be if all the code is simply dumped into a common file.</p><p>There are some cases when it is clear that code should be keptseparate. Some applications, such as our web store example, may haveadministrative pages where employees can update product information,modify product categories, etc. Those tasks that require a differentlevel of authorization should certainly be kept separate from thepublic code for security reasons. Administrative code should beplaced in a separate subdirectory, such as<em class="filename">/usr/local/apache/cgi-bin/web_store/admin/</em> thatis restricted by the web server.</p><p>If you do choose to separate a CGI application into multiple scripts,then you should certainly create a separate directory within<em class="filename">/cgi-bin</em> for each application. Placing lots offiles from lots of different applications together in one directoryguarantees <a name="INDEX-3151" /> <a name="INDEX-3152" />confusion later.</p></div></div><a name="ch16-10-fm2xml" /><div class="sect2"><h3 class="sect2">16.1.8. Using Submit Buttons to Control Flow</h3><p>Whether or not you break your <a name="INDEX-3153" /><a name="INDEX-3154" /> <a name="INDEX-3155" /> <a name="INDEX-3156" />applications into multiple scripts, youwill still encounter situations where one form may allow the user tochoose very different actions. In this case, your CGI script candetermine what action to take by looking at the name of the submitbutton that was chosen. The name and value of submit buttons is onlyincluded within form query requests if they were clicked by the user.Thus, you can have multiple submit buttons on the HTML form withdifferent names indicating different paths of logic that the programshould follow.</p><p>For example, a simple shopping cart CGI script may begin with codelike the following:</p><blockquote><pre class="code">#!/usr/bin/perl -wTuse strict;use CGI;my $q = new CGI;my $quantity = $q->param( "quantity" );my $item_id = $q->param( "item_id" );my $cart_id = $q->cookie( "cart_id" );# Remember to handle exceptional casesdefined( $item_id ) or die "Invalid input: no item id";defined( $cart_id ) or die "No cookie";if ( $q->param( "add_item" ) ) { add_item( $cart_id, $item_id );} elsif ( $q->param( "delete_item" ) ) { delete_item( $cart_id, $item_id );} elsif ( $q->param( "update_quantity" ) ) { update_quantity( $cart_id, $item_id, $quantity );} else { display_cart( $cart_id );}# That's it; subroutines follow...</pre></blockquote><p>From looking at this section of code, it is easily apparent how theentire script reacts to input and the role of each of thesubroutines. If we clicked on a submit button represented in an HTMLform with <INPUT TYPE="submit" NAME="add_item"VALUE="Add Item toCart">, the script would call the <tt class="function">add_item</tt>subroutine. Furthermore, it is clear that the default behavior isdefined as displaying the shopping cart.</p><p>Note that we are branching based on the name of the submit button andnot the value; this allows HTML designers to alter the text on thebutton displayed to users without affecting our <a name="INDEX-3157" /> <a name="INDEX-3158" />script.</p></div></div><hr align="left" width="515" /><div class="navbar"><table border="0" width="515"><tr><td width="172" valign="top" align="left"><a href="ch15_03.htm"><img src="../gifs/txtpreva.gif" alt="Previous" border="0" /></a></td><td width="171" valign="top" align="center"><a href="index.htm"><img src="../gifs/txthome.gif" alt="Home" border="0" /></a></td><td width="172" valign="top" align="right"><a href="ch16_02.htm"><img src="../gifs/txtnexta.gif" alt="Next" border="0" /></a></td></tr><tr><td width="172" valign="top" align="left">15.3. Debugging Tools</td><td width="171" valign="top" align="center"><a href="index/index.htm"><img src="../gifs/index.gif" alt="Book Index" border="0" /></a></td><td width="172" valign="top" align="right">16.2. Coding Guidelines</td></tr></table></div><hr align="left" width="515" /><img src="../gifs/navbar.gif" alt="Library Navigation Links" usemap="#library-map" border="0" /><p><font size="-1"><a href="copyrght.htm">Copyright © 2001</a> O'Reilly & Associates. All rights reserved.</font></p><map name="library-map"><area href="../index.htm" coords="1,1,83,102" shape="rect" /><area href="../lnut/index.htm" coords="81,0,152,95" shape="rect" /><area href="../run/index.htm" coords="172,2,252,105" shape="rect" /><area href="../apache/index.htm" coords="238,2,334,95" shape="rect" /><area href="../sql/index.htm" coords="336,0,412,104" shape="rect" /><area href="../dbi/index.htm" coords="415,0,507,101" shape="rect" /><area href="../cgi/index.htm" coords="511,0,601,99" shape="rect" /></map></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -