Reference Library
Main Report

By Duncan Strand

Email me about this page


Table of Contents

Introduction
Design Decisions

Choice of programming language
User interface design
Unique identification
What's new
The system
Good points
Problems, Problems, and more problems
Displaying windows 
strlen()
fgets()
EditForms
ISBN

Search and delete
Evaluation
Improvements to the project handbook
Acknowledgements
Appendix A Development History


Introduction

A reference library currently keeps is records using a manual card system, for a long time this system has been shown to be to cumbersome. They want to change to a computer system, which can do everything the old manual system does, and more. Basically the system must be able to store the details about lots of books, including the authors, and publishers. This program was written to fulfil these requirements.

Throughout the programming of the reference library system I kept a log of all changes to the system as and when they happened, this was updated either at the end of the day or whilst the program was compiling. I also kept a daily backup of the work meaning that I can easily look back at the work done.

The purpose of this document is to document the decisions and problems that were occurred in completing the system. I will list these in the order they occurred.

I will be frequently referring to the system design document. (A copy was included with the project documentation).


Design Decisions

Choice of programming language

This library system was written in C++. There were several reasons for this choice:

  1. Familiarity with the language.
  2. Portability. Although the GUI code is not portable, the core system is.
  3. Speed. C++ can produced an executable that isn’t much slower than if it were written using assembler.
  4. Size. C++ executable are reasonable small (depending upon the compiler).

The compiler used is Borland’s C++ Builder v3.0. The executable is approximately 655K. The program can be run on Window95, Windows NT 4. (Windows 98 has not been tested, but there should not be any problems).

I choose to write the program to use Windows because the compiler was given away on the cover of PC Plus magazine, without which writing the program to use the Windows interface would have been very complicated.

The alternative would have been to write the program with a DOS interface using the MS-DOS characters to draw the interface on the screen. In many ways this is harder than writing a program for windows, because there are no methods provided that allow the programmer too easily create the interface

User interface design

There are three basic types of window in the program, a window either, displays data, adds data, or edits data.

The design of each type of window is different according to the type. Programming practicalities (except for edit type forms – see the problems section) did not influence the design of the user interface.

The show data forms, all have a list of all the items on the right (a details list). The list allows the user to select what item they want to look at. This window is used to display the results of any searches that the user performs.

On the left of the window are fields that display the data. What fields are displayed depends upon the type of form, but generally show the title of the item at the top. As the data displayed in this window should not be changed all the fields are read only.

Occasionally the window will also have buttons that perform a search for the data displayed next to the button. This make it easier for the user to use the program.

The edit windows were originally similar to the show windows, with a list of all the data held by the system. This was changed because it created a problem of when to make any changes the user made to the data. They are now very similar to the add data windows.

There are other windows displayed by the system. The first window displayed to the user, for example, was the last window to be designed. Deciding what controls, if any, should be available via it was not difficult, deciding how they should be placed in the window was.

There did only seem to be one option, label each button so it gives its full functionality, i.e. "Add Book", "Show Author", to do this would have resulted in the screen containing to much for the user to be able to immediately take in. Eventually I realised that using the group box would provide a way of grouping the buttons with similar functions together in a way that would not be to confusing to the user.

When designing the user interface I have tried to create the "look and feel" that is synonymous with all Windows software.

Unique identification

Each entry in the library is uniquely identifiable. The ISBN number identifies a book. A copy of a book by its accession number. An author by their author code, and a publisher by their publisher code.

These identifiers are used to associated authors, and publisher to books, and show which book the copy is a copy of.

Book

Identified by its ISBN. The ISBN number was the most obvious choice, as every book has one.

There is a problem with using the ISBN in this way. Either the system must update the ISBN number throughout the system if the user changes it, or do not allow the user to edit the ISBN.

Book CopiesAn accession number identifies a book copy.
Author

An author is identified by their author code. The author could be identified by their name (be it forename, surname, or full name), however their name cannot be guaranteed to be unique.

Another option would be to not use an author code, but use the object pointer to identify the author.

 

Publisher

A publisher is identified by their publisher code. The publisher could be identified by its name, however their name cannot be guaranteed to be unique.

Another option would be to not use a publisher code, but use the object pointer to identify the publisher.

 


What’s new

This is what has been added and removed since the system design document was written. This does not include any GUI classes.

Three new classes have been added, they are KeyWord, KeyWord_node, and NodeException. No classes have been removed from the design.

The keywords were originally going to be stored in an array in the Book_node class, however I decided that using an array would have been to time consuming (to write) than creating a separate KeyWord class that inherits LinkList. The Book_node inherits the new KeyWord class. The main benefit of this is that there is no limit in the number of keywords that a book can have (originally there was a limit of five). The KeyWord_node class is the node used in the keywords linked list.

NodeException is thrown if the program encounters an error. One of the benefits of this is that if memory allocation fails in a constructor method the program does not exit (as it would in the system design), instead it throws a NodeException.

Not counting methods in the new classes, a total of 37 methods have been added to the original design. 11 methods have been removed. Three attributes were added, and one removed. The only class unchanged (in class structure) was Book_Author_node.

Almost all of the new methods were added when I started writing similar methods for various parts of the GUI. Many of these methods were placed into the core code.

For a definition of what the new methods do, refer to the project documentation.

Author

New methods 
removeANode()Groups two methods into one action, the deleteAll() and removeNode() methods.
search()A the time of writing the system documentation the fine details of how searches were to work had not been decided. This was added as part of the solution.
Removed methods 
addNode( Author_node Author_node )Removed because it wasn’t being used.

Author_node

New attributes 
titleThe authors title. Added as many books to give the authors title.
forenameNot a new attribute. This was swapped for the initials attribute.
New methods 
getTitle()Get the authors title.
setTitle()Set the authors title.

Book

New methods 
removeBNode()Groups two methods into one action, the deleteAll() and removeNode() methods.
search()A the time of writing the system documentation the fine details of how searches were to work had not been decided. This was added as part of the solution.
Removed methods 
addNode( Book_node Book_node )Removed because it wasn’t being used.

Book_Author

New methods 
removeBANode()Groups two methods into one action, the deleteAll() and removeNode() methods.
search()A the time of writing the system documentation the fine details of how searches were to work had not been decided. This was added as part of the solution.
countAuthor()Added when methods like this were appearing throughout the GUI part of the system.
deleteBookAuthor()The problem with using ISBNs as a primary key is that the user needs to be able to edit them As ISBN numbers are used to link authors to books, changing a books ISBN ‘lost’ all its authors. This method was written to help to avoid this. It deletes all the entries in the list with the passed ISBN, allowing another part of the code to re-add the authors with the new ISBN.

Book_Copies

New methods 
removeBCNode()Groups two methods into one action, the deleteAll() and removeNode() methods.
search()A the time of writing the system documentation the fine details of how searches were to work had not been decided. This was added as part of the solution.
countCopies()Added when methods like this were appearing throughout the GUI part of the system.
updateBookCopies()The problem with using ISBNs as a primary key is that the user needs to be able to edit them As ISBN numbers are used to link book copies to books, changing a books ISBN ‘lost’ all its copies. This method was written to help to avoid this. It updates the list with the new ISBN.
deleteBook()A quick way of deleting all the books with the passed ISBN.
Removed methods 
addNode( Book_Copies_node node )Removed because it wasn’t being used.

Book_Copies_node

New methods 
getStateOfRepairT()Returns the state of repair as a string.
setStateOfRepair()Originally the user typed the state of repair field, but this was updated so that they selected it from a list.

Book_node

New methods 
copy()Copies the passed book into the instance of this class. This includes the keyword list.
getIssueDate()
setIssueDate() 
The association between this class and the cDate class hasn’t changed, except that the instance of cDate is now private. The reason for this is that the exact publication date of a book is not something the user is likely to know. So with these methods they need only know the year.
Removed Attributes 
KeywordsReplaced the need for this by adding the KeyWord class.

Book_Publisher

New methods 
removeBPNode()Groups two methods into one action, the deleteAll() and removeNode() methods.
search()A the time of writing the system documentation the fine details of how searches were to work had not been decided. This was added as part of the solution.
deleteBookPublisher()The problem with using ISBNs as a primary key is that the user needs to be able to edit them. As ISBN numbers are used to link publishers to books, changing a books ISBN ‘lost’ all its publishers. This method was written to help to avoid this. It deletes all the entries in the list with the passed ISBN, allowing another part of the code to re-add the publishers with the new ISBN.
Removed methods 
addNode( Book_Publisher_node node )Removed because it wasn’t being used.

Book_Publisher_node

New methods
setPublisherCode()Left out of the system design by mistake. According to the system design there was no way of setting this.

cDate

New methods
setDate()Set the date using a string.

ISBN

New methods
loadISBN()Load an ISBN number from the passed file. Added to avoid replicating the same code.
saveISBN()Save an ISBN number to the passed file. Added to avoid replicating the same code.

LinkList

New methods
countNodes()Used in place of a findNext search to count the nodes in the list.
getFirst()Originally the last, current, and head pointers were all public. This was changed to reduce the chance to them pointers being changed. This, though returns the first (head) node.
Removed methods
addNode()Removed both the addNode methods to reinforce the need to inherit this class, and not use it directly.
loadList()Not needed.
saveList()Not needed.

Publisher

New methods 
removePNode()Groups two methods into one action, the deleteAll() and removeNode() methods.
search()A the time of writing the system documentation the fine details of how searches were to work had not been decided. This was added as part of the solution.
Removed methods 
addNode( Publisher_node node )Removed because it wasn’t being used.

Publisher_node

New methods
removeNewLine()Saving a new line characters (they are "\r\n") can cause problems. When loading a file the new line characters can be misinterpreted as being the end of a string. To avoid this the "\r\n" pair is replaced with "&n".
Removed methods
Publisher_node()Removed all but the default constructor. Removed before NodeException was added. Because there was no way for the constructor to return a value to say if the data was added ok I decided that it was better to remove them.

ReferenceLibrary

New attributes 
filenameThe filename (including path) of the last loaded or saved file. Added as a usability feature, otherwise the user would need to do a "Save As" whenever they want to save the data.
DataChangedAnother usability feature. Its used to remind the user that they have not saved their data when the close the program.
New methods 
dataChanged()Called when the data has been changed.
getDataChanged()
setDataChanged()
The usual get and set methods for the DataChanged attribute.
setFilename()
getFilename()
 The usual get and set methods for the filename attribute.

The system

The finished program has all the functionality of the system described in the system documentation.

Each book can be associated with, many authors, many publishers and many copies. To accomplish this some extra lists of data are used, they are:

Book_Copies
Accession#ISBN
10-19-861188-9
20-19-861188-9
30-86288-162-5
40-415-11647-3
A view of the book copies list

Each book can have 0 or more copies. All the copies of all the books are stored in this list.

Each row in the list is unique, the accession number ensures this.

The ISBN number is used to identify what book this is a copy of. Using the ISBN we can look through the book list for the entry with the same ISBN. The ISBN number is, in this list not unique.

The example shows four copies in the library, two of the copies are of the same book. The other two are of different books.

Book_Author

ISBNAuthor code
0-415-11647-31
0-415-11647-32
0-415-11647-33
0-19-861188-94
0-19-861188-96
0-86288-162-56
A view of the book author list

Each book can have one or more authors. All of the book – author associations are stored in this list.

Each row in the list is unique. There is no unique identifier for each row. The combination of the ISBN and author code is unique. Using the ISBN number we can search the book list for the details of the book. Similarly, we can search through the author list for the details of the author.

The example shows the authors for three books, with one of the authors having written two books.

There is not, currently, the ability to distinguish between the main author, or co-author of a book, however, adding this feature would only require an extra field in this list. (A boolean).

Book_Publisher

ISBNPublisher code
0-415-11647-31
0-19-861188-92
0-86288-162-53
0-86288-162-52
A view of the book publisher list

Each book has one or more publishers. All of the book – publisher associations are stored in this list.

Each row in the list is unique. There is no unique identifier for each row. The combination of the ISBN, and publisher code is unique. Using the ISBN number we can search the book list for the details of the book. Similarly, we can search through the publisher list for the details of the publisher.

The example shows the publisher of three books, the last book in the list is published by two different publishers.

Good points

I think that the good points of the system are:


Problems, Problems, and more problems

A number of problems were encountered when programming this project, some of them serious, some of them not. The more serious problems are listed here. The development history included in Appendix A documents the less serious problems, and when they happened.

Displaying windows

There are several pats of the GUI which display a form for the user to select some data (for example, select an author to associate with a book).

The method used to display a form is Show() (e.g. AuthorDetails->Show()). It would be expected that the Show method would only return when the user closes the form that was displayed – it doesn’t. The Show method immediately returns. So he following code won’t work:

AuthorDetails->Show();
associateNode = AuthorDetail->selectedNode;

Because the selected node is read before the user has selected an author.

To get around this either the AuthorDetails form needs to block access to selectedNode until the form is closed, or, tell the form that opened it that it has been closed.

The better of the two methods is to block the access to the selectedNode until the form is closed. This can be achieved using semaphores. However the semaphore functions provided by Windows a difficult to learn how to use, so I decided to have the AuthorDetails form tell the form which displayed it that it has been closed.

This introduced another problem. When, selecting an author it is possible to edit the author. Doing this causes the EditAuthor form to update the AuthorDetails form. Doing this makes the AuthorDetails for think it was displayed by the EditAuthor form, and not the (for example) AddBook form.

This was overcome by only telling the AuthorDetails form that displayed it when the selectedNode attribute is needed.

strlen()

The strlen() function returns the length of a string, but doesn’t count any terminating characters (such as "\n", "\r", or "\0"). I overlooked this, when writing the methods that set a string. This meant that when a string was being set, a new string was created 1byte shorter than required. This caused access violations, and possibly a corrupted disk drive.

This bug appeared early in the development of the system. Finding the problem was difficult – it could have been any number of things, but once found was easily fixed (by adding 1 to the result of strlen()).

fgets()

This function reads x number of characters from a file, stopping either when it has read all the characters it was told to read, or when it reads a new line character ("\n").

For all but one string attribute this is acceptable, but the publishers address attribute does contain new lines. So when the data was loaded the first line of the address was loaded, ignoring the rest of the string. When the postcode was loaded the second line of the address was loaded, this effected all the data in the file after the publisher address.

To overcome this the program replaces "\r\n" (a carriage return and new line) with "&n". When the file is loaded these to characters are not removed, they are removed by the getAddressNL().

EditForms

The edit forms originally looked like the show forms, but with editable data. This included a list of all the data. If the user changed some of the data, and then clicked on another item in the list the changed would be lost (the changes are only made when the user clicks on the ok button). An example of such a list is shown to the right.

There were a few ways around the problem:

The solution to this problem that I used was the first one because it was easy to implement. The (previously unseen) advantage of this is that there is only one way for the user to view all the data, previously the user could have used the edit forms to view the data and accidentally edited data.

ISBN

Changing a books ISBN number would cause it to loose all its authors, publisher, and copies. Why? Because the ISBN number is used as the books unique identifier, it is used to associate the book with authors, publishers, and the accession numbers. This was happening because the Book_Author, Book_Publisher, and Book_Copies lists were not being updated with the new ISBN.

Possible fixes for this are:

Search and delete

When searching through a list (using the findNext() method) with the intention of deleting all the returned nodes, there is potentially a problem. If the first node in the list is matched it will be deleted, but the findNext() method relies on the first node always being the same, so deleting the first node makes the findNext() method think it has searched the entire list.

The simple solution to this is to only delete the first node returned by findNext() after all the other nodes have been returned.


Evaluation

There are a few changes that I would have made to the program, if I were to start again.

  1. The LinkList class would be a template class. This would remove all the separate list classes, and the LinkList class would be more reusable than it currently is.
  2. A string class would have been created, and used. As is currently is there are a lot of char pointers used, some of which might not be being deleted.
  3. The NodeException class would be removed, and replaced with smaller exception classes. Each class would be for a specific type of exception.
  4. The speed of the system can be improved. The Book_Author, Book_Publisher and Book_Copies lists all contain references to other lists. Currently the reference followed by searching the list. For example to find the title of a book in the Book_Copies list, the program has to search the book list. This can be speed up by not having to search the book list, and storing a pointer to the book_node in the book copies list.
  5. The GUI part of the code performs too much error checking, sometimes duplicating what the core code is doing.
  6. Given more time the library would be able to store a picture of the front cover of the title. The pictures would be stored as JPEG files.
  7. MS Access is capable of importing text files as tables, the format of the text files can vary, but Access can handle this (the format that the file is in is decided by the user). I would like the system to export the data so that Access can use it.
  8. Many books are available in electronic form on the Internet, the ability to search for these, or at least link to the relevant web site.

In a commercially available system there a many more features that I would expect to find:

The search capabilities should be able to understand written text, for example typing "Search authors forename for Fred" would match all forenames that are Fred. Also none of the numerical searches have greater or less than functions.

Multi-user support would be highly desirable for a real system, because a library would have many users. This current system would need some extensive modifications to enable this. Some of the changes required would be:


Improvements to the project handbook

The layout of the handbook could be improved, some of the problems are:

  1. Heading 7 is on the bottom of page 6, section 7 starts on the next page.
  2. Indentation of the lettering on pages 3, 7, 8, 11, 12, 14 does not line up.
  3. A hand written report – on a computing course?
  4. Define how early a deliverable should be for it to qualify as being considered early.

Personally I think that having to hand in a printed copy of the program source code is unnecessary (and wasteful), so long as it is included on the disk handed in with the project. Is the lecturer really going to look through it all?


Acknowledgements

PC Plus. They put Borland C++ Builder on the May ’98 cover disk. They put Borland C++ Builder 3 on the May ’99 cover disk.


Appendix A
Development History

January
28/1
Book_list appears to be working. A few simple test fail to crash my computer ;-)
Added method copyDate to the date class.

29/1
Fixed a bug in the freeList methods that would cause NULL pointers to be freed.

30/1
ISBN is now a separate class, instead of a string. This is because as, there are several ISBNs are used in the system it makes more sense to have it as a separate class.

February
1/2
Some access violations may have caused the file system on my c: drive to loose a lot of files (all windows files). Still don't know why, but have managed to stop the access violations. (The mess it caused took about a week to fix – with several re-installs of Windows).

4/2
Changed the names of come of the classes to make their use more obvious:
Author_list = Book_Author
Book_list = Book_Copies
Publisher_list = Book_Publisher
Similar changes have been made to the node counterparts of the above classes.

8/2
FileI/O will be via the standard C functions (fopen etc...). This is to allow greater portability. The alternative would have been to use the Windows functions.
Added the File menu to the main window. Contains load, save and exit (all non-functional).

9/2
Tested Book_Copies linked list with 500,000 nodes, and 1,000,000 nodes.
Performed some tests with a large amount of nodes. This showed that some speed increases were needed, particularly for the freeList method (in all classes).

10/2
Publisher now has a freeList method that does something (it was empty).
All lists are now all have addNode() and freeList() methods complete.
Added save methods to Author and Book_Author.
Changed Book class so that only the year needs to be set. This means that IssueDate is now private and getIssueDate() and setIssueDate() have been added. This is because it is unlikely that the exact publication date will be known.
Removed all non-default constructors from publisher, as they cannot return a value if they failed to set an attribute.

11/2
Tested the other classes with large number of nodes (see 9/2), all failed.
Recreated the project from scratch (the makefile not the code). Did this because the original project was originally intended as a quick test, but was beginning to evolve into something a bit bigger.
Added the stats window.
Have finally found and fixed the bug detected on 1/2. What happened was that when strings were being allocated their length was determined via strlen() which doesn't count the NULL terminating character. This character was still being copied into the destination string (via strcpy()), which would cause the problems when the string was deleted. Stupid thing is though, that when writing the string allocation code I was aware that this might be a problem.
All data is now saved.
Author and bookAuthor have working load methods.

12/2
Added the KeyWord and KeyWord_node classes.
All lists are now loaded from disk.
If a string wants a new line in it then "&n" is to be used as opposed to "\n". Reading a "\n" in a string from disk causes the fgets function to stop reading. The "&n" is translated to a "\r\n" as needed.
Started working on the show details form. This works thus: There is a template form, which contains the entire basic layout for the form. Each details window inherits this template and can make any relevant changes.

14/2
Fixed a bug where loading the library data twice didn't free the original data.
The book details window now shows the ISBN of the book selected.

15/2
Fixing the above loading bug introduced another one, (caused AccessViolations for an unknown reason). This is fixed. (When a data file is loaded a new pointer to ReferenceLibrary is created then data loaded into that and the old one deleted).
The Book details window displays all data (except keywords). All list classes (except keywords) now have search facilities to some degree (these will be expanded as deemed necessary).
The main form is now disabled when a window is displayed that would be seriously effected if the data were to change. For example it is not possible to be viewing some book details, and with the same window still open proceed to load new library data. The main window will only stay active if the sub window is unaffected by any changed to the data.
Book_Author_node, Book_node, Book_Copies_node, and Book_Publisher node will directly inherit the ISBN class instead of using a pointer to it. This will make the code more readable because there is less of it.

16/2
Added the list of keywords to the Book details window.
To match all nodes in a list (i.e. findNext returns every node) the mAll boolean should be set to true. This is a change to the original specification.
Added title attribute to author_node. Added get+set methods. Changed all code to deal with new attribute.

17/2
KeyWord class now has search facilities.
KeyWord is now inherited by Book_node, instead of Book_node having a pointer to KeyWord.
Added and finished the author details window.
Added a getAddressNL() method to publisher_node. This converts '&n's to '\r\n's.
Added and finished the publisher details window.

18/2
Clicking on either show buttons on the book details will show either the author details or publisher details (which ever is appropriate).
Added the Book Copies details form. The list of books is slightly different than with other forms. Normally just the a string is stored, in this case a string is stored along with a copy of the selected Book_Copies_node. This allows the system to know which book copy is selected when the details are being displayed.
Added the getStateOfRepairT method. It returns the state of repair in English.
Added the Add book window (unfinished).

24/2
Add book now fully works.
Created a new class called "NodeException". It is throw by the program. This is a better alternative to checking all set<attrib> methods with if statements.

March
10/3
Removed the ability to add the same keyword to a book.
You can now add new authors.
Add publisher now works.

11/3
Edit author is now available.

17/3
Performing an action that would cause any changes to be lost causes a prompt to ask the user if they want to save the data.

30/3
Got Borland C++ Builder3 and upgraded the project to use this.

31/3
Added the following:

Delete author
Delete publisher
Search for author by author code
Search for author by initials
Search for author by title
Search for book by accession#

April
1/4
Added the following searches

Book title
Book isbn
Book issue date (limited)
Book Keywords
Book state of repair (limited)
Search for author of book
Author surname

All (string) searches can either find an exact match or a sub string match (i.e. searching for "the", would return "Rogets Thesaurus"). By default all searches are exact matches.

2/4
You can now print a list of all authors (shows how many books in the library they have written), and a list of all books in the library (including duplicates).

8/4
Changed the edit forms so that there is no list of all the available data. When there was a list of the data, as shown on the right, editing some data, then selecting another item would cause the changes to be lost (it would have been possible to get around this). To edit data the user must now go via the "Show" menu, select the data they want to edit, perform the changes then click on ok. The (previously unseen) advantage of this is that there is only one way for the user to view all the data, as previously the user could have used the edit forms to view the data and accidentally edited data.

9/4
Fixed a bug where changing a books ISBN number would cause the author and publisher details for the book to be lost. This was because the bookAuthor and bookPublisher lists were not being updated with the new ISBN#.
Added a form that allows the user to change the details for each individual book.

12/4
Finished the edit book form.
The books issue date is now selected via a drop down list, in place of a text entry field. The list shows dates from 0AD to the current year.

14/4
Fixed a number of bugs in the edit book form:

Changing the ISBN would result in the book loosing all its copies, all its authors and all its publishers.
Adding new copies of the book works. (Previously it didn’t do anything)

15/4
The search form now includes publisher details, which can be searched for.

25/4
Changed authors initials to authors forename.
Any changes are now a result of testing and will not be documented here.