Register Now
Member Count: 163,450 - July 23, 2008  [Get Time]
Login
Dashboard > TopCoder Competitions > ... > How to Compete in Component Development Competitions > Component Development Tutorial
TopCoder Competitions View a printable version of the current page.  
Component Development Tutorial
Added by dzieba , last edited by ivern on Jun 10, 2008  (view change)
Labels: 
(None)

I. Introduction

Developing at TopCoder

TopCoder develops components in C# and Java. Though the languages may be substantially different, the process is rather similar. This tutorial will cover the development process, from start to finish. Where the process is substantially different, information will be given for each language.

Development Process

The development process, at a high level, is simple. You are tasked to convert a component design, prepared by the designer and reviewed by the Design Review Board, into a functional component. When you have completed your task, your submission will be reviewed by the Development Review Board. If you are the winning developer, you are then tasked to make changes required and recommended by the Review Board. Once complete, your component undergoes a Final Review, and you're done!

TopCoder provides considerable documentation about its design and development processes; if you have not already done so, you should peruse the TopCoder Software development document archive (available here). The TopCoder Member Guide, Development Design and Review Scorecard, and Jalopy Configuration File documents should all be of interest to you. The documents will show you what is expected of your submissions, and the Jalopy configuration will even help you get there.

Required Software

You may write your source code in any environment you wish. However, we rely on certain technologies to build and package our components. Also, we rely on reference libraries common to each language. Exact packages are listed below.

One tool common to all languages here at TopCoder is the TopCoder UML Tool

C#

Tool URL Description
Microsoft .NET Framework v1.1 MSDN SDKs If you're interested to develop in C#, you probably already have this installed. It is available through Windows Update, or through the link at left.
NAnt Homepage NAnt is a utility that executes custom, extensible build scripts. You will need this tool to compile your project and submit your code to TopCoder. Build scripts are covered in more detail in Section III.
NUnit Homepage NUnit is a framework that will allow you to quickly and concisely test your code. Unit testing is covered in more detail in Section VI.
TC Code Documenter [Homepage] The Code Documenter is a command-line utility that writes API documentation in a manner similar to JavaDoc for Java and nDoc for C#/.NET 1.0.  The target language is C#.

Java

Tool URL Description
Sun J2SE SDK 1.4.2 SDK Download Page Java development is normally performed against the latest JDK. You should keep up to date with the latest edition from Sun.
Ant Homepage Ant is a utility that executes custom, extensible build scripts. You will need this tool to compile your project and submit your code to TopCoder. Build scripts are covered in more detail in Section III.
JUnit Homepage JUnit is a framework that will allow you to quickly and concisely test your code. Unit testing is covered in more detail in Section VI.
Sun J2SE JRE 1.3 JRE Download Page Though our components are developed for the latest J2SE environment, we try to support older JREs as possible. Often, development projects will require the component to build against the 1.3 runtime environment. Many Windows systems will already have this in a location such as C:\Program Files\JavaSoft\JRE. Search for rt.jar.
Sun J2EE SDK 1.4 SDK Download Page Only a few components will require this package. Check the Requirements specification for the project you are interested in before installing this software.
Jalopy Homepage Jalopy will format your source appropriately, when used with TopCoder's configuration file (available here). This can save you quite a bit of time.
Checkstyle Homepage Checkstyle is a format checker. You should check your source code format with Checkstyle before submission, if possible.

Be sure to configure your system environment as required by [N]Ant. Also, note the locations of your xUnit installation; the location may be required later to configure your build script.

Registration

To participate in any development contest, you must first register with TopCoder Software. Registration not only allows you to submit design and development solutions, but also allows you to compete in TopCoder algorithm competitions. To register, follow this link.

II. Picking A Project

Picking a project is the first step to a winning development submission. You can quickly find open development contests at this page. From that page, you can see which projects are open, when registration ends and when submissions are due. These dates are very important. You must indicate your interest to develop a solution by the "Registration Ends" date. Your entire solution, complete with tests and documentation, is due by the "Submit by" date. Also important is the complexity level. The higher the complexity level, the more difficult the project may be. However, personal evaluation is usually a lot more useful than the complexity level.

Project Details

Clicking on the name of any project will bring you to the details for that project. Here you will find detailed information about the project, links to documentation for the project, payment information, and a more comprehensive timeline.

Deciding On A Project

After finding a project that interests you, familiarize yourself with the design documentation for the project. The most concise document is the requirements specification. This document will contain information about the various technologies involved in the project (e.g. SSL, LDAP, ODBC). If you are still interested, you can read the component specification, which will be a much more detailed guide to implementing the component. There are other documents available, but these are the most important to determine if a project is right for you.

Before choosing a project, it is very important to ensure you will have enough time to complete the project. Consider your other responsibilities and assignments for the scheduled development period. Also, keep in mind that the component may use some technology you are not familiar with. Do you know how to use database connections in C#? Do you know how java.lang.ref's classes are used? Do you know enough about a certain network protocol to implement a component which requires it? Be sure to review sections 1.2, 1.3 and 2 of the component specification to ensure you are familiar with the technologies employed.

Project Registration

Now that you've found a project you're comfortable with, and you have the time to complete it, you're ready to register! Click on the Register link on the project details page to register for the project.

III. Getting Started - Environment

After registration, you'll have access to the project submission application, as well as a forum for your component.

Project Submit and Review

Project Submit and Review is the central hub for all development and design contests you participate in. You will upload your submission via this application, and you receive your review scores here as well. To begin, go here, and log in. Once logged in, you will see a list of all your open projects, as well as your status.

Click on the name of the project to view the timeline for the project, or to see other more detailed information. At the bottom of this screen, you will have buttons appropriate to the current phase of development. Additionally, there is a button marked "Contact Product Manager". You can use this button at any time to send questions, comments, complaints, or any other information to the Product Manager.

Developer Forum

A link to the development forum for your project is also available from the project detail page. Most communication regarding your project will take place on the forums. Your TopCoder username and password should allow you to view the Developer Forum for your component. If it does not, contact your Product Manager immediately.

Development Distribution

On the development forum, there are four main sections: Design Phase Documents, Design Phase Questions, Development Phase Documents, and Development Phase Questions. You will find the Development Distribution for your component under Development Phase Documents. The Development Distribution should contain all the files and documents necessary to start development on your component.

Java distributions are commonly in jar format, and .NET distributions are commonly in zip format. Both can be extracted with an unzip utility.

Contents

/conf - This directory, if present, will contain configuration files for your component. Sometimes this will include configuration for components your submission will rely on, or sample configuration files written by the designer. If no such files were created during design phase, you may not have this directory in your distribution. If your component uses configuration files, you will need to create this directory on your own.

/docs - This directory contains all current documentation for your component. This includes a .tcuml UML design specification, as well as the requirements and component specification. The design documents are covered in more detail in Section IV.

/lib - Here you will find all required components level libraries that your component will require. Not included here are system level libraries (e.g. ODBC drivers, and other libraries that may required more complicated installation). All TCS components that your project relies on should be included here. If any are missing, you need to contact your Product Manager.

/src - This directory will contain all your source, when you complete your project. In the distribution, normally only a directory skeleton will be created here. Developers are responsible for source file generation, covered in more detail in Section IV.

/test_files - This directory contains all files used by your component during testing. This can include special or extreme configuration files, input and output samples, database schema, and anything else non-compilable your testing needs. The distribution will often contain some sample testing data that the designer has created.

Java

/META-INF - This directory is created by the jar packager, and can be ignored.

/build.xml - This is a default, possibly unconfigured build script. Build scripts are covered in more detail in Section III.

C#

/default.build - This is a default, possibly unconfigured build script. Build scripts are covered in more detail in Section III.

Setting Up Your Environment

First off, you'll need to decide on a working directory. Appropriate examples include C:\working\, C:\proj\, ~/projects/ , or wherever you are comfortable putting your code. It is recommended to establish a new directory for TopCoder projects, to minimize confusion and reduce the chance of submitting the wrong files when you're ready to submit. For this tutorial, we'll assume your working directory is /proj/tc/.

Once you've found a place to store your project, unzip the distribution. This directory (/proj/tc/project-name) will be referred to as your project directory. For this tutorial, we'll assume your project name is tutorial_gen.

The next step is to configure your build script. Keep in mind that TCS will not be using your build script: don't devote TOO much time here. Make the tweaks below to fix paths and library references. If you're having significant problems, check in with your project manager.

Java Build Script - build.xml

The default build script for your project will be almost ready to use. One change you will always need to make is the path to your 1.3 JRE, mentioned above in Required Tools. Find the entry for java_1_3_bootclasspath in the build script. The script is XML, and you'll need to be careful not to change anything unintentionally.

If your path to the 1.3 JRE is "C:\Program Files\JavaSoft\JRE\1.3.1_10\lib", the java_1_3_bootclasspath will change to the following:

<property name="java_1_3_bootclasspath" value="C:\Program Files\JavaSoft\JRE\1.3.1_10\lib\rt.jar" />

In many cases, this will be all the configuration you will need to do. If you cannot add the JUnit jar to your classpath, you will need to include it in the build script. Uncomment the section below, and change  

${ext_libdir}/junit.jar

to the correct path.

<!-- 3rd Party Dependencies -->
<!-- <property name="junit.jar" value="${ext_libdir}/junit.jar"/>
-->

If your project requires additional libraries, you will need to configure your build script to account for these during build and run time. There should already be a few commented examples of libraries in the script.

<property name="spell_check.version" value="1.0"/>
<property name="spell_check.jar.name" value="spell_check.jar"/>
<property name="spell_check.path" value="spell_check/${spell_check.version}"/>
<property name="spell_check.jar" value="${tcs_libdir}/${spell_check.path}/${spell_check.jar.name}"/>

This allows for easy configuration of different versions of the library with minimal build editing. You may have noted the reference to:

${tcs_libdir}

This should already be defined at the top of your build script as follows:

<property name="tcs_libdir" value="lib/tcs" />

This configuration would look for the spell check library jar at /proj/tc/tutorial_gen/lib/tcs/spell_check/1.0/spell_check.jar. Odds are your distribution will already have the proper library path, but if not, you can alter your build script as appropriate, by changing the path or file name property above.

Once you have your jar references set up, you will need to add them to the buildlibs property in your script.

<path id="buildlibs">
<pathelement location="${spell_check.jar}" />

<!-- .... other library references .... -->

<pathelement location="${j2ee.jar}" />
</path>

You must include any library your component requires to build or run. While it can be useful to rely on your classpath, it is good practice to include all the necessary libraries here.

Java - topcoder_global.properties

As you may (or may not) have noticed, the build.xml that came with your distribution contains a reference to a file named "../../topcoder_global.properties". Using this file, you can set properties that won't change between projects, such as the path to your 1.3 JRE.

The format is simple (and common to all Java properties files).

propertyname=value

First, create topcoder_global.properties in the directory below your project (if your current project is/proj/tc/tutorial-gen, your properties file will reside in /proj/tc). Now, you can set properties for all your build scripts. For the JRE, you would add:

java_1_3_bootclasspath=C:\Program Files\JavaSoft\JRE\1.3.1_10\lib\rt.jar

You can add comments to the file, as well.

# I need a comment to remember what this means.
java_1_3_bootclasspath=C:\Program Files\JavaSoft\JRE\1.3.1_10\lib\rt.jar

You can also use property expansion.

java_home=C:\Program Files\JavaSoft\JRE\1.3.1_10
java_1_3_bootclasspath=${java_home}\lib\rt.jar

Keep in mind that your topcoder_global.properties reference is at the beginning of your build.xml. This means that properties from the build.xml won't expand in your properties file (they aren't yet defined). Also note that properties set in the topcoder_global.properties will always override properties set in the build.xml. For more information, see the Ant documentation.

C# Build Script - default.build

NAnt build scripts are very similar to Ant build scripts.

The major change you will need to make is the path to your NUnit installation. Find the line below in your build script, and replace the path with the proper path to your nunit.framework.dll.

<property name="Nunit" value="D:\Program Files\NUnit V2.0\bin\nunit.framework.dll"/>

If your project requires additional libraries, you will need to configure your build script to account for these during build and run time. .NET is somewhat more flexible with binary locations, but it is always good practice to place your libraries in the /lib directory.

<property value="${tcs_bin}\generic_parser\1.0\TopCoder.Util.GenericParser.dll" name="generic_parser.dll"/>

IV. Getting Started - Development

You've got your environment ready, your distribution extracted, your build script configured. Now what? Well, the first step is reading the design documentation.

Design Documents - Your New Best Friend

The /doc directory is chock full of information you will need to complete your submission.

.tcuml - There should be one UML document in the doc directory. This will contain definitions for all classes and interfaces present in the component. It will define all the behavior you will need to implement, including failure conditions.

.pdf / .rtf - There should be one Component Specification and one Requirements Specification present in the doc directory. The Component Spec is a more reader friendly version of the UML document. It summarizes the general design of the component, as well required standards and algorithms for the component. It concisely defines Exception classes and other information you will need. The Requirements Spec is present, but you should not need it. It defines the design requirements; all these should already be met.

.gif / .png - These documents are generated from the UML documentation and can be disregarded. All information here will be more easily accessible in the UML document.

Development Process

As explained in Section I, your part in the development process is to implement the a design which has already been created and reviewed. To this end, you should consider the public API in the design document as canon. You are not allowed to deviate from the public API without approval from the Product Manager and/or the designer. This includes: adding or removing public classes, methods, and interfaces.
This is not to say that every design is flawless; quite the opposite. There is almost always room to improve any design. However, disagreements with design decisions are fixed by design revision, not by development. The implementation phase of the development process is not the appropriate time to remedy design issues, unless they are fatal to the project. TopCoder employs a fully reviewed process for all design changes.

If you have any improvements or insights for the next revision of the design, please post them on the forum. If you do happen to run into any problem during development, bring them up, immediately, on the development forum. The earlier any conflicts or issues with the design are noted, the sooner they can be fixed. If appropriate, read up on the design forum posts. It is possible that issues have already been identified and addressed there. Again, if you see anything that hasn't been addressed, please bring it up in the development forum... it can't hurt!

All this being said, you are encouraged to make any possible improvements on the underlying implementation. If you can refactor the behavior of the public classes into a private helper class: go for it! If you can come up with a more efficient data gathering or manipulation algorithm than the one specified by the designer: wonderful! The only part of the design set in stone is the public API and the general behavior of the component from the user's perspective. Basically, you can't change the "what" of your project, but you do have some freedom to improve the "how."

Development Innovation

Different designs allow for different degrees of development-phase innovation. This is partly a matter of the complexity of the design itself, and partly a matter of the designer's approach. It is possible for a design to describe the component so completely that component coding is reduced to a translation of pseudo code from the Component Specification into the appropriate language for the component. It is also possible for the design to be restricted to definition of the public API, leaving the developer to provide all other implementation details. Most designs, however, fall somewhere in the middle.

Implementation of method bodies is always an area in which developers have an opportunity to put their own twist on the development. With some designs it may also be reasonable or even necessary to add private or package-private methods, constructors, or even whole classes that are not specified explicitly in the design documents. If and when you make such additions you should take care to ensure that they are both necessary and appropriate because these parts of the submission are likely to attract extra scrutiny from the Development Review Board. Developer additions (like any other element of the component), should generally have the narrowest possible scope and the most restrictive access that are consistent with their intended usage. Be sure everywhere to use the most appropriate types of objects and primitives for the tasks at hand.

Generating Stubs

The first step in concrete development will be stub generation. Stubs are compilable code skeletons. Where you would normally find a function body, however, there is simply a "stub." The stubs feature the full API of the final component, but none of the logic. The TopCoder UML Tool can generate stubs for you.
Keep in mind that the stub code you receive will likely not be compilable. You'll need to ensure that approximations and external references are resolved. For instance, in a .NET component, the designer may have had to create stand in objects for system types. You'll need to delete these.

Another common problem with generated stubs is the association section. Many relationships (such as aggregation and composition) in the UML document will be inappropriately translated to code. You are responsible for ensuring the proper translation of the API documentation (the UML document and the Component Specification) to compilable code.

Project Structure

The source for your project will reside under /src in your project directory. At this point, your project should be arranged similarly to the following (under the /proj/tc/tutorial_gen/ directory in the example case):

Path Description
conf/ Any configuration files necessary to your component.
docs/ All the documentation for your project.
lib/ All your local libraries.
src/ All your source code will be placed here (including test code).
test_files/ All non-compiled files used in testing will be placed here.

Java

The code for your component will be stored in the /src/java/main/ directory. From there, you need to arrange your source according to the package for your project. For instance, if your component was com.topcoder.util.tutorial, your full path to source would be /src/java/main/com/topcoder/util/tutorial/. Below are Java specific paths.

Path Description
lib/tcs/spell_check/1.0/spell_check.jar In this example, a component that the Tutorial Generator relies on. Your component may not depend on any components, or it may depend on many.
src/java/main/ Your component code will reside in this directory.
src/java/main/com/topcoder/util/tutorial/ In this example, this is the appropriate place for stubs. In your project, the path will be different.

C#

The code for your component will be stored in the /src/csharp/main/ directory. From there, you need to arrange your source according to the package for your project. For instance, if your component was TopCoder.Util.Tutorial.dll, your full path to source would be /src/csharp/main/TopCoder/Util/Tutorial/. Below are C# specific paths. Although C# namespaces do not require directory arrangement conformity as Java packages do, it is TopCoder practice to arrange the source files according to namespace.

Path Description
lib/TopCoder.Util.SpellCheck.dll In this example, a component that the Tutorial Generator relies on. Your component may not depend on any components, or it may depend on many.
src/csharp/main/ Your component code will reside in this directory.
src/csharp/main/TopCoder/Util/Tutorial/ In this example, this is the appropriate place for stubs. In your project, the path will be different.

Building Your Project

Once you have generated and cleaned your stubs, you should be able to build your component with the build script. To do so, you simply execute your build tool from the command line, with a target.
Here are the common build targets for [N]Ant:

Target Name Description
compile This target will compile your project into a fully functional binary unit (assuming that your code is correct).
compile_tests This target will compile your tests. It depends on a successful compile.
compile_targets (Java Only) This target will compile your component against the 1.3 JRE you configured. Normally, you must build against this target, to pass screening. Section 2 of the Component Specification should detail whether or not you need to compile_targets.
test This target will execute your tests. It depends on a successful compile_tests. After test execution, the results can be found in the /log directory.
clean This target will clean the /build directory, removing all compiled code and intermediate files from the project.
dev_submission This target will create a packaged submission for you to upload via Project Submit and Review, when your project is complete.

To execute a build target, you simply move into the directory where your build script is (it should be the project root directory), and execute ant <target> or nant <target>. Make sure that you've properly configured [N]Ant to allow execution at the command line, or this step simply won't work!

Example NAnt Build

Example Ant Build

Your component should almost always build cleanly against the stubs. If they do not compile, you probably have an API problem, or a library configuration issue. It is far easier to fix these issues now, before you have written any tests or code, and you should do so if possible.

And You're Off!

At this point in the tutorial, you should be ready to develop your project. Any more specific information on development technique or strategy is beyond the scope of this document. However, for the next few sections, we'll walk you through documentation, unit testing, and common problems during development, common to all projects.

V. Working Towards Your Submission - Documentation

Documentation is critical to a useful, maintainable component. If you document your code as you write it, you probably won't even notice the burden of writing a project's worth of documentation. Your submission will be assessed on the quality of documentation. Furthermore, the better your documentation is, the easier it will be for the Review Board to understand and evaluate your code, and the better your overall score will be.

API Documentation

Autogenerated API documentation from the UML document is intended for your consumption, not for the final product. In Java, the API is documented through javadoc comments, and in C# via XML comments. All classes, interfaces, methods, and variables must be documented. Below are examples of each type:

Java

Many Java IDEs (such as Eclipse or IDEA) will automatically generate API documentation as you type.

/**
* Saves the file to permanent storage, on the path specified by configuration. The path
* must not begin with a backslash, and must not contain any special characters (see component
* specification). If the filename cannot be used, an exception will be thrown.
*
* @param filename The filename to save to. May not be null or empty.
* @throws IllegalArgumentException If filename is null.
* @throws IllegalArgumentException If filename is not valid (zero length, invalid characters, etc).
* @throws IOException If an error is encountered while saving the file.
*/
public void SaveAs(string filename)

For more information on javadoc commenting, please see http://java.sun.com/j2se/javadoc/writingdoccomments/index.html.

C#


Visual Studio.NET will create much of your XML documentation for you, as you write your code. Simply type /// before a declaration.

/// <summary>
/// Saves the file to permanent storage, on the path specified by configuration. The path
/// must not begin with a backslash, and must not contain any special characters (see component
/// specification). If the filename cannot be used, an exception will be thrown.
/// </summary>
/// <param name="filename">The filename to save to. May not be null or empty.</param>
/// <exception cref= "ArgumentNullException">If filename is null.</exception>
/// <exception cref="ArgumentException">If filename is not valid
/// (zero length, invalid characters, etc).</exception>
/// <exception cref="IOException">If an error is encountered while saving the file.</exception>
public override void SaveAs(string filename)

Though C# does not have checked throws, it is good practice to note expected exceptions that the function can generate in your API documentation. For more information about XML documentation, see http://msdn.microsoft.com/msdnmag/issues/02/06/XMLC/default.aspx.

Documentation Content

Explain how the component will behave, invalid input, failure behavior. If the object mutates based on certain operations, make sure this is clear (though List.add(object) is obviously a mutator, List.screenedAccept(object, bool) may not be so obvious [even if it is obvious to you!]). Make sure to document the return value, all thrown exceptions, and all parameters. Additionally, every class and interface in your project should have summary documentation, explaining its general function and place in your component.

You should not include any personally identifiable information in your submission. Anywhere you would use your TCS handle (for instance, in an @author tag), put TCSDEVELOPER. This helps keep review as impartial and objective as possible. After you win, you'll change your code to include your handle (during Final Fixes).

Documentation Audience

The audience for your API documentation will be the consumers of the component; TopCoder Software's customers. Always keep a professional tone in your API documentation. Write in an active voice. Be as descriptive as possible, and consider that the consumer of the component may not be as familiar with the language, or the component, as you are.

As mentioned above, documentation from the UML source will not be appropriate to the final product. For instance, you might have received the following documentation for the SaveAs function above:Pull the path info from the config file, then append the filename passed in. Attempts
to save the file to that location, throws exception otherwise.

Invalid Input: null, blank, funny characters, non-fs safe
Valid Input: everything else

Throws: IOException on failure, InvalidArgumentException if it isThis documentation is certainly descriptive of what the SaveAs function does, but it is more a guideline for you, the developer, than descriptive documentation for the user. You'll want to remove the implementation details, and explain, clearly and concisely, how the function behaves. Also, "funny characters" may be appropriate documentation for internal development, but is not appropriate to go to a customer. You should rewrite the API documentation as you complete each function, with these guidelines in mind.

Inline Documentation

Inline documentation are simple comments which explain code function within code blocks. Documentation here is intended both for possible component consumers, as well as internal TopCoder improvement. As with any programming, the more documentation you add, the easier the code is to maintain. x+; is obviously incrementing x. No documentation necessary. Or is there? loopIndex+ might be more appropriate, or recordCount++, and so on. If the intention of your code is not plainly obvious, perhaps you need some commenting!

Required Documentation

There is no hard and fast rule for correct API or inline documentation, and review here will be highly subjective.

However, there are some basic requirements.

  • Every file must contain a TopCoder copyright notice.
  • All public API elements MUST be commented fully (parameters, return types, exceptions). NOTE: This includes Unit Tests.
  • Any overly complex or large block of code should contain some inline commenting to explain purpose and function.
  • Documentation must be professional in tone and quality.

Keep in mind the guidelines in this section, and you should score well on your documentation!

VI. Working Towards Your Submission - Unit Tests

Every component, big or small, requires a set of tests. These tests are meant to probe the component for correct behavior when given proper input, as well as correct failure when given improper input. Our style of unit testing originates from Extreme Programming. You don't necessarily need to program in this style, but for more information on the thought and methodology of unit testing, see http://www.xprogramming.com or http://junit.sourceforge.net/#Documentation.

In Extreme Programming, you write tests before you write code. Again, this is not required, but it can be very useful. Your API is largely immutable, so you should be able to write tests against the API, regardless of their success. Use this fact to your advantage, and test often. As you fill in the stubs, more tests will pass.

What Are Unit Tests?

Unit tests are programmatic tests for the correct functionality of a piece of software, at the finest granularity possible (i.e. tests for each unit of functionality.) This normally means tests of each individual non-private method and constructor of each class. Tests should verify correct operation across the spectrum of legal state and inputs, including extreme values, and also should verify correct failure behavior for every testable failure scenario.

Test Scope


Unit tests can be as extensive as you like. In some cases, your tests may include more code than the unit you are testing!

For every public function in your component, you must have a corresponding test. You should test accuracy and failure (valid and invalid input). The wider range of input and output you test, the more likely you are to expose bugs. It is very difficult to test the full range of input (sometimes impossible in large input spaces). However, the closer you can approximate the full range of input, the more robust your code will be.

In addition to these small, atomic tests, you should always create tests that probe the expected function of your component, from start to finish.

Creating Your Tests

The first thing you'll need to do is create a directory for your tests. It'll be under your src/ tree. Each language is a bit different for testing purposes.

Unit Testing Tips

It can be very tempting to simply aggregate all of your unit tests into one function. However, this greatly reduces the utility of your tests. In our example above, we could easily combine all three test functions into a single function, testSaveAs(). Instead of having three tests, we now only have one. If any of the three behaviors are broken, all tests will fail. In larger scale testing, this composite testing methodology can lead to very confusing failure conditions, and it can become difficult to debug your testing code. The smaller and more atomic your tests become, the more obvious the failure point and probable cause generally are.

  • ALWAYS implement a tested version of the demonstration from the component specification.
  • ALWAYS provide a meaningful message in assert and fail calls.
  • ALWAYS document your test code as well as you document your component code.
  • Break up your tests into discrete TestCase classes. If one TestCase becomes unmanageable, don't hesitate to break it into two or more classes.
  • Break up your tests within those classes into the smallest functions possible; this way, it is clear which areas of the component are failing. You can then use the number of tests passing and failing as a completion metric, as well.
  • Reduce code duplication and increase robustness with setUp() and tearDown().
  • Test every public function for as much valid and invalid input as time allows.
  • Test expected component processes: loading, processing data, and saving data, for instance.
  • Don't forget to clean up your environment! Unit tests should leave the system in the same state they found it in; there should be no persistent changes. This is checked during development review.
  • Test classes are normal classes in every respect, except that they have special significance to the testing framework. These classes can inherit from a class intermediate between themselves and the final test. They may contain methods other than test methods. They may have state.
  • Because they are in the same package or namespace as the component classes they test, the unit tests can access package-private and protected classes and their members.
  • Interfaces cannot be tested directly, but methods that accept interface arguments can be presented with alternative implementations. This technique has great potential for verifying that the component does the expected things with and to its interface-typed fields and method arguments, and that it reacts correctly to exceptions thrown by methods invoked on such arguments.

VII. Working Towards Your Submission - Problems

During the course of development, you may run into any number of problems. You may need a component from the catalog. There may be some flaw in the design that blocks development. You may have questions about the designer's intent, or some technology employed by your component. Have no fear, you're not alone!

If you find any confusion or ambiguity in the design, bring it up on the forums for your component (available from Project Submit & Review). It's possible that you've found some case or situation that the designer may not have thought of. It may be that you're misreading the component, or overlooking something. In any case, problems specific to the component itself should be addressed on the component forum.

On the other hand, if you have problems writing your code, or if you don't understand a required technology, or bugs in that regard, you should probably go to TopCoder's Round Tables, and not the development forums. The TopCoder Round Tables are available at this URL: http://www.topcoder.com/rtables/index.jsp. The General, or Component Competition Forums are appropriate places to start looking for help. The Round Tables are frequented by many of the highly experienced TopCoder members, as well as TopCoder Software staff, who will always try to help as best they can.

If you ever have a problem that blocks you from working on your project, email the Project Manager immediately. This includes things such as missing or corrupt files, access or application problems, and major design issues. You can email your Project Manager from the Project Submit & Review Details page for your component. If you can't access Project Submit & Review, email service@topcoder.com, and indicate which project you're registered to, and the nature of your problem.

The proper method of communication is NOT a readme file. If you need to make any significant deviation from the design, you need to get in touch with the designer and PM.

VIII. Submission!

The hard work is over, and you've got 150 successful unit tests. You're ready to submit your solution!

First, you should review your code. Make sure that your submission meets the review guidelines (Section IX) as fully as possible. Finding small issues now will save you points later in the review process. Make sure that your directory structure is appropriate as above.

Secondly, make sure your code compiles. If you're writing a Java solution, make sure that the compile_targets build target compiles, if applicable.

Finally, run the dev_submission build target. This will build a compressed archive of your files. Make sure to verify that all the files you've written are in the archive, and add any missing files as needed. Your submission should include a successful log from your unit tests, all the files in the conf/ tree, and all the files and directories you need in test_files/. If you have time, you can extract your dev submission to another directory and ensure that it builds cleanly.

Once you're satisfied with your submission archive, you can upload it through Project Submit & Review!

Making your Submission Shine

In order to win development competitions it is necessary to make your submission outshine your competition.
This can be quite a trick for very simple, highly specified components, and should be of considerable concern even for more complex or more loosely specified components. There are many ways to put that shine on your submission, but here are some suggestions:

  • Write clean, clear, efficient code. Even though there is no review line item specifically for this, reviewers are nevertheless likely to react better to code that is easy for them to read and understand. With efficient code you get a potential performance advantage in stress and benchmark testing, as well as likely kudos (and a few extra points) from the reviewers.
  • Write a comprehensive unit testing suite. Inadequate tests can cost you dearly because there are several review line items pertaining to the unit test suite. Tests should cover all non-private methods thoroughly, and they should be well documented. Doing a good job on the tests can be a big win because the unit test suite is one of the areas that are more frequently neglected.
  • Provide excellent documentation. The class and method documentation is the developer's responsibility, and few developers seem to give it the attention it deserves. Good documentation will be clear and comprehensive. Read and become familiar with Javadoc's docs. Note, for instance, that more or less arbitrary HTML can be inserted into documentation comments; appropriate use of that feature can be very effective. Try to put yourself in another developer's position and ask yourself what you might possibly want to know about the component - then put it in. Read and follow Sun or Microsoft's guide on writing comments for the respective language, and also their related documentation on how to write API specifications.
  • Fully satisfy all requirements and provide all required functionality. Perhaps this should go without saying, but it will hurt your chances if anything is left out. Watch out for special cases and unusual inputs.
  • Pay attention to any issues that the designer may have disregarded or overlooked - thread safety, for instance, or portability (even Java and .NET software can have portability issues). Where you have discretion within the design, give your submission desirable properties such as these.

IX. Review

The submission is out of your hands, and the Review Board will judge it on the following criteria. You can find a very detailed summary of the scorecard here.

The implementation addresses the functionality as detailed in the component design documents. - Does your component function as the design specified? Does it do everything required, in the manner required?

The implementation correctly uses the technologies that are specific to the component. - Does your component use all relevant technology properly? Do you connect to the database properly? Do you use proper XML configuration? This also applies to design elements such as singleton design, and synchronization.

The implementation properly implements required algorithms as defined in section 1.3 of the Component Specification. - If there are any complicated algorithms in your component, they are likely specified by the design. If you have improved the algorithms, you can earn extra points here. If there are any problems with your implementation of the algorithms, you will lose points. If you find any problems with the specification in 1.3, you need to bring it up on the forum, and find a solution with the designer. As the developer, you are responsible for the proper behavior of your component, even if there was a flaw in the algorithm design.

All classes, methods and variables declarations are exactly as they are defined in the design documents (visibility, types, modifiers, names, exception list). - As above, you must conform exactly to the API in the design. Removing, adding, or altering public API elements is unacceptable without prior approval from the designer or PM.

No additional public or protected entities are present in the design. - You may only add private entities to the component.Package private and protected variables are not allowed. Package private methods are allowed, as long as they fit naturally into the design. Package private classes are allowed also, if they are used to provide helper methods. Private variables, methods and inner classes are allowed. All added entities must follow the language naming conventions and must use proper English. Note that when there are multiple packages, helper classes may need to be public. In this case the restriction about adding public classes and methods is relaxed.

The implementation properly maps class relationships. - This point is generally implicit if you have implemented the design as specified. You should not add dependencies or associations between classes unless necessary.

The object types defined in the implementation are the best choice for the intended usage. - As a developer, you will have to make choices for object types. For instance, you may decide to use a TreeMap to store some value mappings. Unless you need to preserve key ordering, you should probably use a HashMap instead. The "best" choice here is generally related to efficiency.

There is no useless code. - Don't write sloppy code, and don't reinvent the wheel. Both C# and Java library code can copy arrays, and convert collections to arrays automatically. Don't rewrite library code. Don't make assignments to variables you never reference. Don't leave testing or temporary functions and code in the component.

There is no code redundancy. - Factor code out into helper functions or classes wherever possible. Use intelligent overloading to reduce code duplication. Still, don't go too far to this extreme. Balance your code to minimize duplication as much as possible without ending up with 50 one line functions.

The code is clear and efficient. - This is somewhat subjective, but there are objective references. You probably shouldn't go more than one level with the ternary if operator (e.g. good ? "great!" : ok ? "I suppose" : bad ? or_is_it ? "darn" : "phew" : "who knows?"). This is not clear. Similarly, large blocks of code... if you're getting more than 50 lines in a single function, you can probably break it up into multiple functions. For example, if you're drawing a graph, you can have a drawAxes() function, a drawData() function, and a drawLegend() fuction, rather than a very large block of code. As for efficiency, small things can make a big difference. Break out of a search when you've arrived at the desired value. Set intelligent sentinel conditions, use short circuit evaluation. Don't overcomplicate your code, and try to simplify whereever possible.

The thrown exceptions provide suitable error messages and cause (where appropriate). - Like documentation, exceptions should be concise, detailed, and professional. "IT SCREWED UP AGAIN" is not an appropriate exception message, no matter how appropriate it may feel at the time.

All code, including test cases, follows the TopCoder coding conventions. - Our coding conventions are the published standards for Java and C#. You can view them at the following links:

Java Coding Conventions

.NET Coding Conventions

The implementation code contains detailed documentation for classes, methods, and variables, written in Javadoc / XML style as required by the Java / C# coding standards. - See the documentation section for more information. The documentation should be detailed, comprehensive, and professional. You will also be judged on grammar and spelling.

There are no errors and no warnings while generating the Javadoc / XML documentation. - The documentation must be syntactically correct: no documentation for elements that no longer exist, no inappropriately anchored or malformed documentation elements.

Unit Test Cases thoroughly and correctly test all methods and constructors. - Unit tests are very important, and you must thoroughly test your component. See the Unit Test section above.

Unit Test cases contain an implementation or a demonstration of how the component will be used. - You should test the component as it will be used. The component specification will usually contain an example case of use, and you should implement a test for proper behavior.

Where applicable, Unit Test Cases properly configure the test environment. - Make sure to take advantage of configuration files and setUp() and tearDown() to receive a good score here.

Where applicable, files used in Unit Test Cases exist in the /test_files directory. - If your component requires files to perform tests, they should reside here. If they don't, you'll lose points.

Where applicable, Unit Test cases do not leave temporary files on the file system, open network or database connections, open files or streams after testing is complete. - Tests may be run very frequently by TCS or our clients. It is imperative that the tests leave the system in the same state they find it, and leave no debris.

The unit test code contains detailed documentation for classes, methods and variables. - Your unit test code must be documented exactly as your component code.

Additionally, each of the three development reviewers will write unit tests that will probe your component for accuracy, proper failure, and performance under stress. Your component will be awarded a score based on each of the above points, and those tests.

X. Appeals

After review is complete, you will have a few days to view and appeal the score your component was given. You'll see the comments from the Board on each point above, and you can dispute any score. Please keep in mind that you must have a very good reason to appeal, or it will be denied. If the reviewer makes a statement that is in conflict with the design, or if the review has made an oversight, feel free to appeal. On the other hand, matters of opinion may not be appealed. If you are the winning developer, you will have the opportunity to discuss reviewers' judgments in Final Fixes...

XI. Final Fixes

Congratulations! You're the winning developer!

However, there is probably still work to be done. Your review scorecard will be available via Project Submit & Review, and there you will find any and all problems the Review Board found with your submission. It will contain required and recommended fixes to the submission as received.

Every single required fix must be addressed. Your component WILL NOT be completed until they are. Every recommended fix should be attempted. Obviously, they follow the required fixes in priority, but if there is time, they should be completed.

Communication

More than any stage of the component, communication during final fixes is key.
If, for any reason, you have a question or comment on the review, post it as soon as possible. If there is any blocking issue, email the PM immediately, and post to the forum. The PM will look into the issue, and ensure that the primary reviewer is on top of things. If, for whatever reason, you feel a required fix is impossible, you need to address it on the forums. Do NOT just resubmit without the fix done, or a comment in a readme. This is never acceptable. Communicate with the reviewers to avoid these conflicts! The more detail you can give, and the sooner you give it, the more smoothly this stage will go. The Review Board is always open to communication from the developer; they may have overlooked something in the design or in your submission. Don't be afraid to question the Review Board. Questions and comments show that you're paying attention and actively involved; without communication, the Review Board doesn't know that you're working on the fixes, and can't clarify their requirements.

XII. Final Submission and Review

This is just another dev_submission build. Follow the same guidelines above for ensuring all your files are uploaded properly. Try to be as complete as possible before resubmitting. This saves everyone time, including you.

If you've met all the requirements, and all the review tests still pass, the component is complete, and goes into preparation to be added to the catalog. Your work is complete!

If anything is not done, you've earned a return trip to Final Fixes.

XIII. Conclusion

That concludes this development tutorial. You've registered, developed, tested, submitted, been reviewed, appealed, won, fixed, and finally submitted once again. You've earned your payment, and will receive royalties from your work going forward. Again, congratulations. What better way to celebrate than finding another project to register for and doing it all over again?

It should be noted that this is somewhat out of date since I wrote it, and should probably be cleaned up and updated.

 I think it would also be helpful to add sections on how to do standard setup for database connections etc, and hold reviewers to the same standards.

Posted by adamselene at Oct 11, 2007 13:18

hi,

can you write part for new competition architecture, when you update architecture.

Posted by itanasov at Jan 12, 2008 16:20

Where is the TopCoder's configuration fileof Jalopy?

Posted by hhbhhb at Apr 13, 2008 11:32