Informatics 2 - Software Engineering - 2015/16

Coursework 3

To get started, you will need Additional information important for completing the project will be posted below. When changes are made the Change Log entry below will be updated and an email sent out to the class.

Change Log


Minor bugs in provided code

Thanks to those students who pointed out these bugs by email and on the forum.

Event equality bug

There is a bug in the equals() method of the Event class. If you have not already read the discussion forum post about this earlier in the week, you might want to challenge yourself to find the bug in your Event class unit tests before reading on.

If you read the provided code for this method, you will see the comment

// Check header tuples for equality
and notice that an implementation of this check is missing. In my haste to write and release the code, I added the comment to remind myself to insert the code, but then overlooked following through.

Actually the missing code needs to check more than equality of the headers, it ought to check too equality of the first two arguments of each argument list. The bug is fairly innocent as, when execution of this equals() method in the coursework reaches this point, the form of the first two arguments and the header tuple arguments can be exactly predicted, so this equality check for these components would have always returned true, if it had been implemented.

To fix the bug, replace the comment mentioned above with the comments and code:

// Check leading arguments (first two args and header tuple 
// of each arg list) for equality.

List<String> leadingArgs = messageArgs.subList(0, 2 + tupleSize);
List<String> eLeadingArgs = e.messageArgs.subList(0, 2 + tupleSize);
if (! leadingArgs.equals(eLeadingArgs) ){
    return false;
}

// Gather rest of tuples from each arg list.
I recommend fixing the bug just so your unit tests of Event.java all pass. However, before fixing it, make sure your unit tests are thorough enough that they detect it in the first place! As I mentioned above, when you are doing system tests, you will never run into the bug.

Avoiding problems with dates and times

For the supplementary task involving implementing further use cases, you need to schedule the Clock to notify your method to process charges every midnight. This involves passing the Clock scheduleNotification() method a Date object for an example midnight time, as well as specifying that the interval between notifications should be 24 hours.

To do so correctly is somewhat subtle, because the conversions to and from the formatted dates used in the coursework (e.g. 3 08:00) and the internal time representation use by Date (a long integer) take account of the default time zone used by your Java implementation and also the possibility of being in daylight savings time. In fact, the rules the standard Java library classes (pre Java 8) use for applying daylight savings time corrections seem arcane. A daylight savings time correction seems to be applied even when the time being converted and the current time are both mid-winter. Java 8 introduces a new set of time and date classes to address shortcomings in the earlier support for date and time.

For this coursework, the simplest solution is to ensure that Java is set to use coordinated universal time (UTC) when your tests run. You need to do this before tests are run and before the Clock class sets up its format for parsing and pretty printing times. I suggest adding the line

TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
as the first line of the static block in the Clock class definition, and a
import java.util.TimeZone;
in the Clock class's import block. A static block is a member of a class definition that starts with the keyword static. It defines code that is used for initialising a class's static fields.

Ensuring distinct tests use distinct clock objects

The provided Clock class is a singleton class - there is only ever one instance of the class. The provided implementation creates this instance object in a static initializer block and this single clock object is shared by all tests. As a consequence, second and subsequent tests start at the last time set in the immediately previous test.

Under normal circumstances I don't expect this to be observable, as all executions of your code start with a triggering input event sent into your system and, just before the event is sent in, the sendEvent() method in the event distributor class sets the clock time to the time in the input event.

However, the timedNotifications field of the clock object holds a list of all the objects who should be sent notifications at regular scheduled times. This is never reset between tests, so when second and further tests are run, notifications continue to be sent out to the clusters of objects created for each of the earlier tests, and these clusters never get garbage collected. It is very unlikely you will observe this behaviour. Still, it is inelegant that it goes on.

It would be better if the general testing principle that each test runs on a completely independently-created state were followed fully. Do this as follows:

  1. Remove
      
       instance = new Clock();
    
    from the static block in the Clock class.
  2. Add a new static method to the Clock class:
      
        public static void createInstance() {
            instance = new Clock();        
        }
    
  3. Add the static method call
        Clock.createInstance();
    
    at the start of the implementation of the Hub class constructor in Hub.java.

Using Eclipse or some other IDE

It is strongly recommended that you use Eclipse or some other IDE for developing your code. Useful features include refactoring support to keep your code clean, JUnit support, automatic recompilation, and an integrated debugger where setting breakpoints and checking program state is quick and simple.

If you use Eclipse you can get started as follows:

  1. As in Section 4.1 of the handout, download the "bikescheme.zip" file and unzip it in some temporary location in your file-space to create a directory tree with top-level directory "BikeScheme".
  2. Start up Eclipse. These instructions have been tried out using Eclipse Mars (4.5). Very likely something similar works with earlier versions.
  3. In Eclipse, create a new Java project using File > New > Java Project. This opens up the first page of the new project wizard.
  4. Choose a "Project name" for your project, ideally without spaces. Here will assume the name is "Edbikes".
  5. JRE JavaSE-1.7 or JavaSE-1.8 are both fine as choices for the execution environment.
  6. Select "Create separate folders for sources and class files". Click "Configure default..." to check the source folder is "src" and the output folder name "bin". Click OK on this "Preferences (Filtered)" page.
  7. Click "Finish" to create an Edbikes project folder in your Package Explorer view with a "src" subfolder.
  8. Select File > Import. In "Import" pop-up window, select General > FileSystem. Click "Next".
  9. In the "File system" box use the "Browse" button to select BikeScheme directory created from the unzip. In the white box below, tick the box by "BikeScheme". The "Into folder" should be set to "EdBikes". Click "Finish". You should now see in the Package Explorer the full "src", "data", and "lib" directory trees. Assuming you have autobuilding enabled, the source files will not compile properly because JUnit library information is missing. The next step is to provide this information.
  10. Select your EdBikes project directory in the Package explorer and open a Properties window for the project using Project > Properties. Select the "Java Build Path" property, select the "Libraries" tab and click "Add JARs...". Select both the JUnit and the Hamcrest ".jar" files in the "EdBikes/lib" directory and click OK. Click OK again in the Properties window.
  11. The Java source files should now all compile fine, and you should be able to both run individual JUnit tests and the AllTests class as a Java application.

Version control

You might well want to take this opportunity to try using version control for your project. If nothing else, this will back up your code and make it easy to work on shared code. There are a number of free private repository hosting services available on the web. If you are new to version control, I recommend you start with subversion rather than git.

The Subversive plug-in for Eclipse adds support for subversion.

There is no coursework requirement that you use any version control system and no extra marks will be given if you do.

Ways in which the provided code can be modified

You should not modify the provided event framework classes AllTests, Event, EventDistributor and EventCollector.

In the SystemTest class, you should insert your own tests and modify the provided code before the comment "Support code for running tets. Nothing here shoujld need touching".

With the device-related classes, you should only need to add extra code if you work on one of the supplementary tasks.

Feel free to use the provided Hub, DStation and DPoint classes as a basis for classes of your own, modifying them as much as you like. And you are free to add new classes too. For example, you might consider adding User, Bike and Trip classes.

Tabs, indents, and line lengths in Java code

The handout recommends you follow standard coding guidelines such as those from Google or Oracle/Sun. A common recommendation is that you never use tab characters for indentation and you restrict line lengths to 80 or 100 characters. You are strongly recommended to adopt both these recommendations, both because it is good practice and, particularly, in order to ensure maximum legibility of your code to the markers. I recommend using an indent step of 4 spaces as in the Sun guidelines rather than the 2 in the Google guidelines, for consistency with the supplied code.

The default in Eclipse is to use tab characters for indents. To change this, open the Preferences pop-up and navigate to the Java > Code Style > Formatter preference. Edit the existing Profile to create a new Profile that only uses spaces. Say name the new profile "Eclipse no-tabs".

In Eclipse, you can check the right margin setting and turn on a right margin indicator line by visiting the General > Editors > Text Editors preference.

Naming I/O device instances

The tests that markers will run on your code will rely on particular instance names being used for I/O devices that participate in the target use cases. Please follow the naming scheme as used in the supplied demonstration design. The BikeSensor and BikeLock devices are not exercised by the demonstration design, but do participate in target use cases. For these, use names of the following forms:

BikeSensor: x.k.bs
BikeLock: x.k.bl
where x is the docking station instance name, set in the addDStation use case and k is a number in the range 1 .. n, n being the number of docking points associated with the docking station x. In addition, for KeyReader objects associated with docking station terminals (needed for the ViewUserActivity use case), use names of form:
KeyReader: x.kr

If you implement the supplementary design task, you can choose your own instance names for the FaultButton, FaultLight and BankServer devices, as the markers will not be running their own tests on this code.

AddBike use case

While appendix B of the handout does not say so explicitly, the AddBike use case should be very similar to the ReturnBike use case from an input/output point of view. The use case is triggered by a BikeSensor object at a docking point detecting the docking of a bike. Subsequently the OK light at the point is flashed and the lock is locked.

Your system should tell the difference between the use cases by checking whether the docked bike is currently on hire. If it is, the ReturnBike use case runs, if not, the AddBike use case runs.

System-level Tests

For this design, it doesn't make much sense to create each test from a single use case. In nearly all cases, several use cases will be needed to set up some state, followed by one or more to observe the state.

Do not run all your tests together in one large test. Rather create one or more separate tests targeting each functional requirement. Create a section of your report where you list functional requirements, giving each some short identifier name or index (like 1.a). Also give each of your tests a short name or number, and then use a table to show which tests exercises each requirement.

Include all your tests as JUnit test methods in the SystemTest class. Feel free to add extra auxiliary methods that handle repeatedly needed sequences of input and output events, like the provided method for setting up the two docking stations in the provided demonstration design.

Further report guidelines

Your report for the target tasks is expected to be around 7-10 pages in length, excluding title page and any appendices. As possible, put any work you do on a supplementary task in a separate section after the material on your implementation and testing of the target tasks. For example, it may be difficult to create a sensible distinct class diagram for the supplementary task. In this case just put the class diagram(s) somewhere in the report describing your work on the target tasks, and refer to the diagram in the supplementary task section. On the other hand, descriptions of your tests naturally belong in the respective parts of the report.

Your class diagrams need not document in any detail the code in the provided device-related classes and interfaces. Just draw them as rectangular boxes containing their names. And your diagrams don't have to include at all framework classes such as Event, EventDistributor and EventCollector. To show a class implements an interface, you can use the compact lollipop notation, though if the interface class is one you add, you need then also to show it separately as a rectangle with its methods.

When you discuss your tests, it is fine to simply copy-and-paste the relevant lines of Java code setting up the input and expected output events: you don't need to invent any prettier syntax.

You do not have to include any sequence diagrams. However, you might want to include an appendix where you cut and paste the logging events produced by each of your tests into separate subsections. If your logging information is not too verbose, but still shows each object visited during a sequence of method invocations, it serves as a good low-cost substitute for sequence diagrams.

Marking approach for supplementary task

The Coursework 3 instructions identify two possible supplementary tasks you could attempt, and say that 20% of the marks will be awarded for the realisation of one of them. These supplementary tasks are less well defined, more open ended and have more challenging elements to them.

It is typical that Informatics courseworks have components that are open ended, that they offer opportunities for students to be awarded marks for distinctive excellent work that goes beyond what is explicitly requested. This is especially true as you move up the years.

In this spirit, work on a supplementary task will be marked according to a stricter grading scale than the work on the target tasks. In particular, markers will apply criteria similar to the criteria the College of Science and Engineering recommends we use in Honours years. As a consequence a solution to a supplementary task that is technically correct might attract a mark of 6/10 - 7.5/10, rising to 7.5/10 - 9/10 for excellence beyond simple correctness; and anything higher reserved for truly superlative work.

The instructions state that additional marks will be awarded for realisation of one of the two supplementary tasks. Do not submit work on two supplementary tasks. Doing so would not give you the opportunity of getting any higher mark. Distinctive quality, not just quantity, is being looked for on this supplementary task. One supplementary task provides quite enough opportunity for you demonstrate distinctive excellence.

Submission

To make life easy for the markers, please ensure your JUnit system-level and unit tests all run with the exact command sequence listed in Section 4.1 of the handout. There should be no problem with satisfying this requirement. Just don't rename the package all the source files are in, don't rename the "src" directory, and put all your tests in the provided EventTest and SystemTest classes.

To submit your Java files, copy the whole directory tree, starting with the "src" directory, into your "Application" directory where you are collecting your other files. You should not submit your "bin", "lib" or "data" directory trees.


Home : Teaching : Courses : Inf2c-se : Coursework 

Informatics Forum, 10 Crichton Street, Edinburgh, EH8 9AB, Scotland, UK
Tel: +44 131 651 5661, Fax: +44 131 651 1426, E-mail: school-office@inf.ed.ac.uk
Please contact our webadmin with any comments or corrections. Logging and Cookies
Unless explicitly stated otherwise, all material is copyright © The University of Edinburgh