A WebApplication is loosely defined as a piece of software following the standard Web application architecture and deployment model:
Web Browser <-- HTTP --> Web Server <-- SQL --> Database
This architecture poses specific challenges for an ExtremeProgramming ("XP") process. This WikiPage is meant to describe advice in meeting these challenges.
It was spawned from a thread on the xp list: http://groups.yahoo.com/group/extremeprogramming/message/70945?threaded=1
DaveHoover: There is a book on the topic (see ExtremeProgrammingForWebProjects). I haven't read it. I am interested in hearing if anyone else found it helpful. http://safari.informit.com/?XmlId=0-201-79427-6
Carlton:
I've read it. It is mostly OK. Nothing really bad and few good ideas. IMO, the AW books are starting to get repetitive.
I pulled two ideas from this book. One was a technique to separate your business logic from your presentation layer. Nothing really new to me, since that is a struggle in ALL web applications. The second idea was that indeed, in large web applications, you are going to have some specialization. The main specializations I have observed are the programmer/graphic designer divide. The types of experience and knowledge required make it almost impossible to cross this division.
AlexChaffee:
In practical terms, here are some things I've done that make XP's
practices work better in a web project:
- Have a full version of the server and database on every developer's box. This allows every developer to run all the acceptance / web tests (without getting bogged down with netlag, locking/transaction problems, unexpected schema changes, or corrupt data added by someone else).
- Ideally, the entire system can be built and installed from scratch directly from the project directory, ensuring that your developers are going to find the same quirks as on the live box.
- Apply MVC to fully separate your UI code (parsing forms, validating input, building HTML) from your business logic. This allows you to write tests against the clear APIs of the business objects, rather than the murky cgi-strings-in, html-out interface of the running web app.
CurtisCooley: Critical in all applications, but web apps really can bite you hard when
you cheat. Use struts or XMLC to keep these layers separate. We've
gotten really good at unit testing Struts actions and it has paid us
back many times over.
- However, also test the web app! Write scripts that log in, click buttons, enter data, etc. These will take a while to run, but it's worth the effort since these web tests will catch silly things like session problems or broken links or database or configuration errors.
CurtisCooley: JWebUnit is your friend
- Don't rely on your UI templates (like like PHP and JSP) for complex presentation logic. Consider a "dumb" template system like XMLC or roll your own based on static HTML files. If you do decide to use "smart templates", you want to have these templates contain purely superficial layout instructions, and *no* business logic or even, if at all possible, presentation/layout logic.
For an example of that last point, if you have a page that must do a
search, sort the results by date, and return the items on the Nth page
of the results list, don't have the page perform the search or even
select the subset! Instead, the page template should just tell your
business logic the parameters and page number, ask it for an array of objects, and render them in the order
returned.
- Completely separate your data storage layer; build an in-memory version that provides the same interface. Running your tests against this in-memory store will greatly improve performance in tests (making you more likely to run them).
- Don't rely on the database for complex logic; it's easier to both write and (more importantly) *refactor* code written in your preferred high-level language.
CurtisCooley: We had a great DBA who wrote PlSQL for the complex database logic. Like
you, I thought this was a bad idea. But he embraced XP and wrote his own
set of tests and kept the database code cleaner than we kept the Java
code. We were tied to Oracle (though it really wouldn't have been that
much work to switch), but we were very grateful to not have to ever
worry about the DB. All we did was call the correct stored procedure,
and that was unit testable.
If you have a DBA like this, you are truly blessed, so take full
advantage. If not, then heed Alex's advice and keep all the code in the
same language.
See MartinFowler's great article on EvolutionaryDatabaseDesign?
at http://www.martinfowler.com/articles/evodb.html
GeorgePaci:
- Use version control. CVS is free and ubiquitous. You can use CVS over SSH to do all the updates to your live server. I really, really wish we had -- incomplete updates bit us a couple of times, and made us waste lots of time manually (and imperfectly) verifying updates instead of letting the computer do it.
- If, as in the original poster's case, you're using PHP, check out phpUnit (the xUnit port for PHP): http://phpunit.sourceforge.net/
- Put as much display noodling in Cascading Style Sheets (CSS) as you can -- among other benefits, your tests stay much more stable.
AlexChaffee: I echo the recommendation for CVS and CSS. I'd also like to
give a shout out for id attributes. Identifying your page data
elements makes your tests much more straightforward and minimizes
tedious HTML parsing/analysis. Also the span tag is good for
identifying just the relevant bits of your page data without messing
with page layout. E.g.
<span id='customerName'>Tommy Franks</span>
Also
XpathLanguage is a good weapon to add to your testing arsenal; the above is located using "//span[@id='customerName']" . See my
http://www.xpathexplorer.com .
How to use XPath in PythonUnit:
import unittest, urllib
from xml.xpath import Evaluate
import xml.dom.minidom
class IndexTest?(unittest.TestCase):
def __init__(self, methodName='runTest'):
unittest.TestCase.__init__(self, methodName)
self.content = urllib.urlopen('http://localhost/~user/sandbox/').read()
self.dom = xml.dom.minidom.parseString(self.content)
def testTitle(self):
assert Evaluate('/html/head[title="Page Title"]', self.dom)
We use XPath for the most part, but also do occasional
RegularExpressionMatchAssertion against self.content, particularly negative testing (regression testing for things we've removed on purpose). --
KenBitskoMacLeod