How To Write Code In Our Environment
Each organization has a unique development environment that team members are
expected to conform to. In our case, there are two environments we support and
use: Linux and Windows/Eclipse.
Table of Contents
Command line Java on Linux
Eclipse on Windows
Adding a New Project
Stable versus Development Builds
Third-Party Code Issues
Coding Standards
Unit Tests
Acceptance Tests
back to list of contents
- Use standard CVS commands to check out the code from the repository.
- Use ant from the top-level directory of
the Module, e.g. UrbanSim, to compile all the code. The command "ant
jar" creates the jar file for this module.
- Run Junit on the unit tests in the .../tests directory, e.g. taxirus.tests .
- The .../tests directory has accept-test-* subdirectories, each of which
has a run-test.pl Perl file. To run an acceptance test, go to its directory
and execute the run-test.pl file.
- Use standard CVS commands to commit changes back to the repository.
- Be sure that you are following our Development Process when you are committing changes.
David says: This might be
slightly out of date, but the concepts will still work via some set of eclipse
commands. Also, the DevelopersPlayground is a handy way to do acceptance
tests. Ask me if you have questions.
back to list of contents
- Using the "Team" Perspective, connect to the CVS repository.
The Streams subtree lists all the CVS modules. Selecting a module and using
the "Add to Workspace" item will import the code into Eclipse.
- Thereafter, use the standard Eclipse UI to edit, compile, and debug the
code.
- Right-clicking on the project and selecting "Team / Synchronize with
Stream" will open a merge/synchronize browser. The menu items are
fairly self explanatory - for example, "release" causes a CVS
commit of the changes; "catch-up" causes a CVS update; and so on.
- Be sure that you are following our Development Process when you are releasing changes.
- Instructions for running Tinyville in Eclipse are in the DataPrep/examples directory.
- Eclipse allows you to define which editor to use for different files,
according to the file extension. This allows you to get the editor of your
choice when you double-click on the file name in the Package or Search
windows, for instance. For instance:
- To edit .xml files with the standard eclipse text editor:
- Select
menu item Workbench | Preferences.
- In
Preferences dialog box select Workbench | File Editors.
- Press
the upper Add... to add a new File Editor for “*.xml”.
- With
this file type selected, press the lower Add... to add an Associated
Editor of “Text Editor” in the Internal Editors list.
- To edit .htm and .html files with Microsoft FrontPage, do the same as
above except in the last step above select External Program. Scroll down the list and select
Microsoft FrontPage HTML Document. NOTE: eclipse still won't know
about the changes FrontPage makes unless you do Refresh from Local after
making the changes.
- We
have an additional module "DevelopersPlayground"
with various Eclipse specific tests and files. This module is stored in the general
purpose CVS repository rather than the production-code
repository because the module contains logins and passwords that should
not be exposed to the outside world.
Special Case: Starting a New Project
- Eclipse requires two hidden files in each CVS module: .classpath and .vcm_meta
When a new module is created in CVS, but outside Eclipse, Eclipse will not
recognize it until these two hidden files are created. The easiest way to
create them appears to be to copy them from another already Eclipsized
module.
back to list of contents
There are two things to consider when starting a new project/sub-project:
- Directories are used both for CVS modules and for Java packages. We
separate the two uses by having a top-level directory for the module using a
capitalized name (e.g., DemoProject). Under that directory we have
the Java package directories (e.g., taxirus and taxirus/tests). Thus the
full path will include both (e.g., DemoProject/taxirus/tests). This looks a
little confusing until you get used to thinking "module name"
versus "package name".
- The easiest way to create a new project is to do that in Eclipse via the
New command then then use the Team | Share Project menu to put it in the
repository.
David says: I recommend you
keep stable builds around, somehow; you never know when a customer will want a
demo....
back to list of contents
We keep a number of different builds available for users to download.
Developers need to understand what they are and how they are updated, all of
which is documented on another page.
back to list of contents
- Your project will use some standard
third-party packages and extensions, for example, JUnit for testing. The source code and .jar's for these third-party elements live
under third-party in the individual projects.
- If using WinCVS, add jar files using "add binary" rather than
just "add".
back to list of contents
- Use
Javadoc
- Comments
for non-obvious code (don’t bother to comment obvious code). Try to write
obvious code. Make code self documenting.
- No
magic values. Use well named constants where magic values are needed.
- Naming
conventions:
- Packages:
lowercase
- Files:
CapitalizedWithInternalWordsAlsoCapitalized
- Exception
classes: ClassNameEndsWithException
- Constants:
UPPER_CASE_WITH_UNDERSCORES
- Private
and protected instance variables: _leadingUnderscore;
- Local
variables: firstWordLowerCaseButInternalWordsCapitalized
- Methods:
all_lower_case_with_underscores()
- Converter
method return type X: toX()
- Gets
and sets (attribute X of type Y): Y x() or Y getX() (both ok); x(Y) or
setX( Y ) (Both ok)
- Minimize
* forms of import
- Use
JUnit tests rather than the older “main in every file” tests
- Use
interfaces rather than abstract classes; do not use inheritance for
implementation sharing unless you have a good reason
- Avoid
public instance variables
- Explicitly
initialize all instance variables.
- Minimize
the use of static variables. Consider everything to be passed around as an
object.
- Declare
arrays as Type[] array rather than Type array[].
- Write
methods that “do one thing”. Define abstractions that “are one
thing”. Don’t mix behaviors and abstractions at different levels –
it’s just asking for trouble.
- Avoid
overloading methods on argument type. Arity is ok, argument types can lead
to problems when programmer forget that overloading is done with static
types in Java rather than dynamic types.
- Never
fail silently. Never trap an error and ignore it. Never provide an abstract
class with dummy empty methods (use abstract methods instead).
- Declare
local variables at the point where you need them.
- Use
automatic formatting
- Write
less code
- Directories
overlap across modules
- XMLs
and DTDs
- Once
and only once – In a program written with good style, everything is
said once and only once.
- Lots
of little pieces – Good code invariably has small methods and small
objects.
- Replaceable
objects – Good style leads to easily replaceable objects.
- Isolated
rates of change – …don’t put two rates of change together.
- Name
Types Well.
- Choose
Intention Revealing Operation Names.
back to list of contents
Unit tests (provided by the JUnit framework) are the preferred method for running tests on code fragments.
They replace the "main in each class" technique for testing.
A template for a test class can be found in the repository as
taxirus.tests._templateUnitTest.
David says: You'll probably
want to implement something like this.
back to list of contents
Testing is an important part of our development
process. Our Fireman automatic build process
runs both unit tests (tests of individual classes and small collections of
classes) and acceptance tests (a.k.a. integration tests) each time it builds the
systems.
The acceptance tests are Java programs (classes) that extend the urbansim.tests.AbstractAcceptanceTest
class. We currently have:
- A test of UrbanSim, using XML databases of the Tinyville dataset (
UrbanSim/urbansim/tests/accept_test_2_urbansim
)
- A test of DataPrep, using XML databases of the Tinyville dataset (
DataPrep/urbansim/tests/accept_test_1_dataprep
)
- A test of DataPrep and UrbanSim, using MySQL databases of the Eugene1994
dataset (
Eugene1994/tests/accept_test_1_eugene1994
)
Each of these tests consists of the same basic steps:
- Clean up from any previous runs of this test. The reason this is
done first rather than last is that when tests fail, one often wants to
examine the databases and files of the test. If the last action one took
where to clean up, the interesting files wouldn't be around of examination.
- Copy and/or create new test databases. We can't just use the
existing databases because the tests may modify the databases (intentionally
or unintentionally).
- Set up database specifiers. (see below)
- Run the Code Under Test.
- Verify the results. Typically the test has a set of expected
results and the verification consists of comparing the actual versus the
expected. The results are stored both in individual files and in the
databases. In general, the results should be an exact match. Unfortunately,
DataPrep and UrbanSim are currently non-deterministic in various ways and
thus the results may not match exactly. While we decide what to do about
this, we are ignoring those "errors".
Running The Tests
On Linux, the tests can be run using the run-test.pl
script in
each acceptance_test_*
subdirectory.
On Windows using Eclipse, the tests can be run using "Run as JUnit"
on the main class.
$Id:
howtodevelop.html,v 1.16 2002/04/10 20:49:04 bnfb Exp $ |