By: Team T11-3
Since: Sep 2019
Licence: MIT
1. Introduction
1.1. What is Powerlifting Competition Coordinator?
Powerlifting Competition Coordinator is a free application for powerlifting competition event organizers that is simple, fast, and easy to use. It is targeted at organizers of small to medium sized powerlifting competitions who require a hassle-free way of managing and tracking the lifts of participants in and out of the powerlifting competitions. During competition mode, the system has real time maintenance of athlete rankings within their respective weight classes allowing the organizer to track the participants' standings at all times throughout the duration of the competition.
1.2. Core team
Powerlifting Competition Coordinator was developed and is maintained by Team T11-3. Feel free to contact us for any enquries.
1.3. Contributing
Powerlifting Competition Coordinator is an open source project and we would love to involve any contributor who has a passion for powerlifting. To get involved, start by reading Section 2, “Setting up”.
2. Setting up
This section includes the instructions to set up your development environment.
2.1. Prerequisites
Prior to setting up the project proper, make sure you have the following.
-
JDK
1.8.0_60
or laterHaving any Java 11 version is not enough.
This app will not work with earlier versions of Java 11.
You can get the latest Java 1 JDK at this link. -
IntelliJ IDE
IntelliJ by default has Gradle and JavaFx plugins installed.
Do not disable them. If you have disabled them, go toFile
>Settings
>Plugins
to re-enable them.
2.2. Setting up the project in your computer
To setup the project in IntelliJ, follow the steps below.
-
Fork this repo, and clone the fork to your computer.
-
Open IntelliJ (if you are not in the welcome screen, click
File
>Close Project
to close the existing project dialog first). -
Set up the correct JDK version for Gradle.
-
Click
Configure
>Project Defaults
>Project Structure
. -
Click
New…
and find the directory of the JDK.
-
-
Click
Import Project
. -
Locate the
build.gradle
file and select it. ClickOK
. -
Click
Open as Project
. -
Click
OK
to accept the default settings. -
Open a console and run the command
gradlew processResources
(Mac/Linux:./gradlew processResources
). It should finish with theBUILD SUCCESSFUL
message.
This will generate all resources required by the application and tests.
2.3. Verifying the setup
To verify that the setup is completed successfully, you should:
-
Run the
seedu.system.MainApp
and try a few commands. -
Run the tests to ensure they all pass.
2.4. Configurations to do before writing code
This subsection includes configurations that you may find necessary or useful as you work on this project. We recommend that you make these configuration changes and additions before you start writing code.
2.4.1. Configuring the coding style
This project follows oss-generic coding standards. IntelliJ’s default style is mostly compliant with ours but it uses a different import order from ours. Follow the instructions below to rectify this.
-
Go to
File
>Settings…
(Windows/Linux), orIntelliJ IDEA
>Preferences…
(macOS). -
Select
Editor
>Code Style
>Java
. -
Click on the
Imports
tab to set the order.-
For
Class count to use import with '*'
andNames count to use static import with '*'
: Set to999
to prevent IntelliJ from contracting the import statements. -
For
Import Layout
: The order isimport static all other imports
,import java.*
,import javax.*
,import org.*
,import com.*
,import all other imports
. Add a<blank line>
between eachimport
.
-
Optionally, you can follow the UsingCheckstyle.adoc document to configure Intellij to check style-compliance as you write code.
2.4.2. Updating documentation to match your fork
After forking the repo, links in the documentation will still point to the se-edu/addressbook-level3
repo.
If you plan to develop this as a separate product (i.e. instead of contributing to the
se-edu/addressbook-level3
) , you should replace the URL in the variable repoURL
in DeveloperGuide.adoc
and UserGuide.adoc
with the URL of your fork.
2.4.3. Setting up CI
Set up Travis to perform Continuous Integration (CI) for your fork. See UsingTravis.adoc to learn how to set it up.
After setting up Travis, you can optionally set up coverage reporting for your team fork (see UsingCoveralls.adoc).
Coverage reporting could be useful for a team repository that hosts the final version but it is not that useful for your personal fork. |
Optionally, you can set up AppVeyor as a second CI (see UsingAppVeyor.adoc).
Having both Travis and AppVeyor ensures your App works on both Unix-based platforms and Windows-based platforms (Travis is Unix-based and AppVeyor is Windows-based). |
2.4.4. Getting started with coding
When you are ready to start coding:
-
Get some sense of the overall design by reading Section 3.1, “Architecture”.
-
Take a look at [GetStartedProgramming].
3. Design
This section documents the design and interaction of components in Powerlifting Competition Coordinator. Please take a moment to understand the different components before making any code changes.
3.1. Architecture
The Architecture Diagram given above explains the high-level design of the App. Given below is a quick overview of each component.
The files used to create diagrams in this document can be found in the diagrams folder. |
-
At app launch: Initializes the components in the correct sequence, and connects them up with each other.
-
At shut down: Shuts down the components and invokes cleanup method where necessary.
Commons
represents a collection of classes used by multiple other components.
The following class plays an important role at the architecture level:
-
LogsCenter
: Used by many classes to write log messages to the App’s log file.
The rest of the App consists of four components.
Each of the four components
-
Defines its API in an
interface
with the same name as the Component. -
Exposes its functionality using a
{Component Name}Manager
class.
For example, the Logic
component (see the class diagram given below) defines it’s API in the Logic.java
interface
and exposes its functionality using the LogicManager.java
class.
How the architecture components interact with each other
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues the command delete 1
.
delete 1
commandThe sections below give more details of each component.
3.2. UI component
API : Ui.java
The UI consists of a MainWindow
that is made up of parts e.g.CommandBox
, ResultDisplay
, PersonListPanel
,
CompetitionListPanel
, ParticipationListPanel
, StatusBarFooter
etc. All these, including the MainWindow
,
inherit from the abstract UiPart
class.
The UI
component uses JavaFx UI framework. The layout of these UI parts are defined in matching .fxml
files that
are in the src/main/resources/view
folder. For example, the layout of the
MainWindow
is specified in
MainWindow.fxml
The UI
component,
-
Executes user commands using the
Logic
component. -
Listens for changes to
Model
data so that the UI can be updated with the modified data.
3.3. Logic component
API :
Logic.java
-
Logic
uses theSystemParser
class to parse the user command. -
This results in a
Command
object which is executed by theLogicManager
. -
The command execution can affect the
Model
(e.g. adding a person). -
The result of the command execution is encapsulated as a
CommandResult
object which is passed back to theUi
. -
In addition, the
CommandResult
object can also instruct theUi
to perform certain actions, such as displaying help to the user.
Given below is the Sequence Diagram for interactions within the Logic
component for the execute("delete 1")
API call.
delete 1
Command
The lifeline for DeleteCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
|
3.4. Model component
Please note that due to the limitations of PlantUml, the diagram above is unable to show the java generics being used here (e.g. Data, UniqueElementList and others). We also did not delve into the session classes as we felt the diagram would be overly convoluted. For more details, regarding the class interactions for session, please refer to the implementation of competition sessions below.
API : Model.java
The Model
,
-
stores a
UserPref
object that represents the user’s preferences. -
stores the System data.
-
exposes unmodifiable
ObservableList<Person>
,ObservableList<Competition>
andObservableList<Participation>
that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. -
exposes a Session class to handle the context switching between in and out of competition sessions.
-
does not depend on any of the other three components.
3.5. Storage component
API : Storage.java
The Storage
component,
-
can save
UserPref
objects in json format and read it back. -
can save the
Person
,Competition
,Participation
data in json format and read it back.
4. Implementation
This section describes some noteworthy details on how certain features are implemented.
4.1. Context-Switching feature between sessions
Our features are mainly split into 2 contexts. An in-competition, and an out-of-competition session mode. A session is started when the user wants to start an existing competition to call lifters to perform their attempt, record them, and finally to view the ranking leader board for the competition, all within in-session mode. On the other hand, an out-session mode, when the user exits the competition session mode, is where all create, read, update delete of the Person, Competition, and Participation is done.
The reason for this context-switching feature is to prevent users from using out-session commands that are strictly for in-session mode and vice versa.
The activity diagram above shows the average user flow of how the user can go in-session, and also distinctly shows the commands that can be done in each state. However, the end of every competition session does not signify the end of a user’s activity. The user can still go in and out of the competition session (start and end), to perform the different commands from the different states.
4.1.1. How it is being implemented
This is done using an instance of the Session class, which is exposed from the model manager. The session has a competition field to indicate the current competition that is ongoing during the session. If there is no competition set in the session, then there is no ongoing session. Using this simple but highly effective method, we are able to use very simple logic to achieve the necessary context-switching behaviour described in the above diagram.
4.2. In-Session
In-Session is the state where the user enters competition mode, where users can command the app to generate the next lifter, as well as record any attempt. At the end of the competition, the rank of the participants and competition can be viewed too, as long as a competition session has yet to end.
To handle the state of the competition, we have created a new Session
class that is packaged into model and
managed by the ModelManager. The Session
class is a singleton class, and only has one instance in the ModelManager.
The reason behind the use of a singleton class to handle sessions, is that we only want one ongoing session at any
point in time. The singleton class will also only temporarily store its participation list, and participationAttempt
list in relation to the ongoing session. Once the session ends, all data is reset.
Any update in any objects such as the attempts or participation details will be handled by the ModelManager,
which will be explained in more details in the respective features below.
4.2.1. Next feature
One of the main purpose of the in-session function is to generate the next lifter and his attempt details accordingly.
In the Session
class, the list of ParticipationAttempt
is maintained so that athletes can make their attempt
in order of the type of lift, attempt number, and in increasing weight to be attempted. Upon calling the next
command,
the next lifter is called up, and the following lifter should be asked to prepare for his lift, after the next lifter.
Format: next
Given below is the example flow of what the model does when the NextLifterCommand
is executed after being parsed
through the LogicManager.
Step 1: A new NextLifterCommand
is constructed when the user inputs next
in the command box.
When NextLifterCommand#execute()
is called, the model will get the following lifter, and store the
ParticipationAttempt retrieved from Session#getFollowingLifter()
in a local variable,
to be returned together with the CommandResult later on.
Step 2: The ModelManager
will call Session#NextLifter()
to generate the next lifter and attempt in the form of a
ParticipationAttempt
object. If the Session
is not prepared, which means that the imported ParticipationAttempts
are not sorted, prepare()
will be called internally. When this method is called, the ParticipationAttempt list in the
Session will be sorted according to the new ParticipationAttemptComparator
. When this is done, the session is now
prepared, and next or following lifters can be generated based on this sorted list.
(This method is usually called once just after starting the session.)
Step 3: The Session#NextLifter()
method will then return the first ParticipationAttempt
in the list.
This is equivalent to the next lifter to make his attempt, since he is the top most in the sorted list.
Step 4: A new CommandResult
will be returned. Details of the next and following ParticipationAttempt will be
included and displayed in the Dialogue Box to the user.
4.2.2. Lift feature
This command allows the user to update and record the result of the attempt that was just made. The participation’s dependent attempts as well as scores will be automatically updated according to the lifts made and recording using this command.
Format: lift Y/N
Given below is the example flow of how the model executes the AttemptLiftedCommand
in the model after it is
parsed through the LogicManager
.
Step 1: An AttemptLiftedCommand
is created with a boolean parameter to indicate the success of the lift.
An input lift y
by the user will create an AttemptLiftedCommand
, taking in boolean true
.
Step 2: The following lifter and attempt is retrieved and stored in a local variable in the execute method of the command, so that we can prompt the user of the following lifter, before any changes are made to the existing attempts.
Step 3: model#makeAttempt()
is called in the execute method of the command. The ModelManager
will then call
Session#attemptMade()
to indicate the attempt has been made. This method will return a ParticipationAttempt
object
that has just been made, and stored in a local variable named next
. If this particular attempt has already been made,
an exception will be thrown to inform the user in the form of a CommandResult
.
Step 4: The Participation
of the next
will be retrieved, so that we can update the participant’s attempt by
calling Participation#updateAttempt()
. ModelManager#setParticipation()
will then update the participation’s attempt
in the storage accordingly.
Step 5: AttemptLiftedCommand#execute()
will then return a new CommandResult
containing the associated result,
together with the following lifter.
4.2.3. Rank feature
A RankCommand class is created to facilitate ranking of an athlete for a given competition he or she participates in.
Implementation
RankCommand extends the Command Abstract Class, the rationale is explained in Choice of Design Pattern
sub-section of the Rank feature.
Rank feature has 2 sequential checks: 1. Checks if a competition session is ongoing, rank command can only be used if a competition session persists. 2. Checks if an athlete participates in a competition, rank command can only be used if an athlete participates in a competition.
Finally, the feature returns an athlete’s report card for a competition. For example,
Athlete: Alex Yeoh Competition: NUS Powerlifting Open 2019 Rank: 1 Total Score: 1 Max Squat: 1 Max Bench Press: 0 Max Deadlift: 0
When the rank feature is used, RankCommand interacts with other classes to return an athlete’s report card. See the sequence diagram for a high level depiction of how RankCommand interacts with other classes.
Choice of Design Pattern
Original AB3 code base uses a Command Design Pattern, which facilitates execution of different commands, without the programme knowing which type of command is being executed. Furthermore, the original AB3 code base achieves a Command Design Pattern by requiring different types of command classes to extend from a Command Abstract Class.
Due to time constraint and to achieve consistency with the Command Design Pattern of the original Code Base, we decide to apply the Command Design Pattern for the Rank command too.
4.2.4. Ranklist feature
A RanklistCommand class is created to facilitate ranking of all the participants for a given competition that is currently ongoing (i.e. in-session). The ranking can be altered depending on the ranking method chosen by the user. This provides the user a variety of ranking methods to suit the user’s need during a powerlifting competition. Typically, a powerlifting competition usually provides rankings for their participants based either on their overall score or the maximum weight lifted for a particular lift.
Implementation
RankCommand extends the Command Abstract Class, the rationale is explained in Choice of Design Pattern
sub-section of the Ranklist feature.
Rank feature has 1 check: 1. Checks if a competition session is ongoing, Ranklist command can only be used if a competition session is currently ongoing.
Finally, the feature returns a listing of the athletes based on the ranking method provided. For example,
Ranking of athletes by overall score in competition NUS Powerlifting Open 2019: 1. Alex Yeoh (Score: 100) 2. Bernice Yu (Score: 97) 3. Charlotte Oliveiro (Score: 2)
When the Ranklist feature is used, RanklistCommand interacts with other classes to return a participant’s score for a given ranking method before sorting the list and displaying it on the screen as seen above. Please refer to the sequence diagram for a high level depiction of how RanklistCommand interacts with other classes.
Choice of Design Pattern
Original AB3 code base uses a Command Design Pattern, which facilitates execution of different commands, without the programme knowing which type of command is being executed. Furthermore, the original AB3 code base achieves a Command Design Pattern by requiring different types of command classes to extend from a Command Abstract Class.
Due to time constraint and to achieve consistency with the Command Design Pattern of the original Code Base, we decide to apply the Command Design Pattern for the Ranklist command too.
4.2.5. End session feature
This feature ends the session, and shifts the user back to the out-session state. All data stored in the session will be reset to default.
Format: endSession
When we first implemented the session feature, the session can only be ended when a competition has ended, which means there are no more attempts to be made. However, we have now made it such that the user can switch between sessions as and when, even in the middle of the competition. This gives users more flexibility to switch between session states, without worrying about the state of the competition.
4.3. Out-Session
4.3.1. Start Session feature
The start session feature is a command to start a new competition session, when a user is not in competition state.
As mentioned in Section 4.2. above, Session
allows the user to start any competition session as and when, even when a
competition has not ended (there are still attempts left to be made). To start a session, the user can enter
the command with the specified competition.
Format: startSession c/COMPETITION_NAME
Given below is the flow of execution in the model after a StartSessionCommand#execute()
is called.
Step 1: Model#startSession(comp, partList)
is called, where comp
is the Competition
object to start the session
with, and partList
is the list of Participation
who will be participating in this competition session.
The method then calls Session#start(comp, partList)
.
Step 2: An internal call in the start()
method, loadAttempts(p, p.getAttempts())
, is made for every
Participation
object, p
, by looping through the partList
, loading all unattempted attempts into the
participationAttemptList temporarily stored in the Session instance.
(p.getAttempts()
retrieves the list of all 9 Attempt
instance that the participation has submitted at the start.)
Step 3: The loadAttempts()
method will loop through all the 9 Attempt
objects taken in as parameter, and checks if
each has been attempted. If an Attempt
by that Participation
has not been attempted, a new ParticipationAttempt
object will be created and added to the list.
Because of the way Session
handles the initialising of every new session, be it starting a new competition, resuming a
competition, or even starting a session with a competition that has already ended (all attempts have been made by the
athletes) is made possible.
4.3.2. Competition features
There are 4 competition/person features: adding, deleting, editing and listing competitions. The features are briefly described below. The crux of adding and editing a competition commands is the CustomDate class , the CustomDate class is important for validating the starting and ending dates for a competition event. The date validation process will be discussed in detail in words and with the aid of class and sequence diagrams.
Adding a competition
To add a competition, a user supplies the name of a competition and its start and end dates. But, the start date must be equal or before end date.
Deleting a competition
To delete a competition, a user supplies the index of that competition. The index of a competition will be displayed in the user interface of that programme.
Editing a competition
A user has the choice of editing one or more of the following competition fields:the competition name, start and end dates of a competition. But, similar to adding a competition, the edited start date must be equal or before the edited end date.
Listing a competition
To list all competitions stored in the programme.
Choice of Design Pattern
Similar to the Rank feature.
Implementation
As mentioned earlier, editing or adding competitions require start date to be equal or before the end date. To ensure the dates given for a competition are valid, we created a CustomDate class. Please see the following class diagram for more information on the association between CustomDate and Competition classes.
To see the mechanism of the date validation process, please see the following sequence diagram.
Pros of CustomDate:
-
Note that DATE_FORMAT is hard-coded by us (class diagram cannot explicitly show this), this ensures our programme maintains a consistent date format for all competitions.
-
By storing a Date object in the CustomDate class, we enable ParserUtil to call the before() method of the Date class to check for valid dates. Please the sequence diagram for the addCompetitionCommand, which provides illustration on how this is achieved.
Cons of CustomDate:
-
We need to ensure functions/classes which rely on CustomDate can catch and handle errors due to inappropriate date properly. This means that any changes to CustomDate in the future requires some work to propagate the changes to the rest of the code base.
-
Users may wish to have their own date format.
Alternative:
We have considered using only the Java Date object, but we think it will be neater to have a CustomDate class to package a date object and its associated date format string in a CustomDate object. Furthermore, we can recycle the functions available in the CustomDate class for person features too (read the next section).
4.3.3. Person Features
There are 4 person features: adding, deleting, editing and listing persons. Similar to competition features, the programme needs to validate date of birth when a user adds a person or edit a existing person’s date of birth. In particular, the programme needs to ensure a person added or edited will not have a date of birth which occurs in the future. In other words, the person added or edited must have a date of birth equal to or before today’s date. For example, if today is the 11/10/2019, a person’s date of birth must be prior to 11/10/2019 or it must be exactly 11/10/2019.
The features are briefly described below. Similar to the competition features, we will describe the association between CustomDate and Person classes. Subsequently, we will describe the validation process for person features.
Adding a person
To add a person, supply a person’s name, a date of birth and a gender (male or female only). A person must have already been born. Example, if today os 11/09/2019, a user cannot add a person who is borned in 15/09/2019 (in the future).
Deleting a person
To delete a person, supply the index of that person.
Editing a person
For person, a user has the choice of editing either the person name, date of birth or a gender. But, person must have already been born.
Listing people
To list all people stored in the programme.
Implementation
Similar to competition, the crux of editing or adding persons rely on the CustomDate class for date validation.
Please see the following class diagram for more information on the association between CustomDate and Person classes.
To see the mechanism of the date validation process, please see the following sequence diagram.
Pros:
-
Note that DATE_FORMAT is hard-coded by us (similar to Competition features), this ensures our programme maintains a consistent date format for all people.
-
By storing a Date object in the CustomDate class, we enable ParserUtil to call the before() method of the Date class to check for valid dates.
Con: Similar to the Competition section.
Alternative: Alternative consideration is similar to the Competition section.
4.3.4. Participation features
A Participation is an association class we have created for every Person who has participation in a particular Competition. A person can take part in many competitions, and for each competition he/she takes part in, there will be a corresponding Participation class associated to that Person and Competition instance.
Supporting the create, read, update and delete of the instances of the Participation association class
To support the add, delete, and reading of the participation instances using the commands below, the JSON storage system was modified (please refer to the Storage section above) in order to support the many-to-many relationship between competition and person. This allows the association class to be saved which the original Address Book architecture did not allow.
Choice of Design Pattern
Optimally, such many-to-many relationships should be handled by some form of join table on a database. Due to the project restrictions, we mapped a similar structure the the JSON storage system treating each file as a table, attempting to parallel the way real databases worked while still using JSON storage.
Implementation
To achieve this we treated each file saved as a table. Hence, there is a save file for each of the participation, competition and person models. When reading from the JSON storage, the competition and person data are read first, before the participation data is read. This is because the Competition and Person objects need to be created first in order to be associated with the Participation class. Since the names of competitions and persons are unique, we used that to identify the competition and person instances the participation instance that was originally saved was associated with.
Pros:
-
By using a Json Storage, the amount of changes to the Storage system was substantial but minimized, while still being able to support the Participation association class which helped decouple the Person and Competition classes.
Con:
-
The uploading of the participation class from JSON relies on the property that there is some unique data signature of a person and the competitions, which can be determined from the data stored as JSON. Since both Person and Competition extend UniqueELementList, they will certainly be have some unique data signature (i.e. in this case each person and competition have unique names), which can be used to determine the instances the Participation object was originally associated with before it was saved. Hence, the current JSON storage system is not designed extensibly for the developer to move away from using the UniqueElement class for its instances or store data in a way that is not unique to the instances as instances with the same data signature cannot be distinguished from each other using the current JSON storage system.
Alternative:
We have considered using XML storage and/or creating foreign keys using the JSON storage. However, due to the limitations of time and the complexity of achieving such a feature, we settled with modifying the JSON storage.
Please see the following Structure of the Storage Component diagram and check the repository to understand the utility of the Storage system to support the many-to-many relationship.
API : Storage.java
Create a new Participation
To create a new Participation, the associated Person and Competition must exist. If either doesnt, an exception will be thrown to the user through the result box to prompt the user to input an existing one.
Format: addParticipation n/PERSON_NAME c/COMPETITION_NAME s/S1/S2/S3 b/B1/B2/B3 d/D1/D2/D3
Note: S1 means the 1st attempted weight for the Squat and so on.
List Participation
The list participation feature allows the user to filter the participation list on the PCC app based on a particular competition. If no parameters (competition name) are taken in, the command will list out all of the participations stored in the system.
Format: listParticipation
or listParticipation c/COMPETITION_NAME
Delete Existing Participation
The user can delete an existing participation, maybe in the case he/she has withdrawn or is disqualified from that competition.
Format: deleteParticipation INDEX
We have decided to use the index of the participation in the list to delete a participation instead of other parameter types, like the name or competition of the participation. The main reason is because, there may exist more than one participation with the same name and different competition, or different name and same competition.
Pros:
-
Takes in less parameters, user can type less.
-
Avoid complications between unmatched name and competition.
-
Easy to implement.
Cons:
-
User will have to scroll through the participation list on the app to type in the index.
4.3.5. Overall Rank feature
The user can list the persons in the system by the number of times they won a competition.
Format: overallRank
Due to time limitations we have not allowed the user to specify any other ranking method but given the design of our system which is highly extensible, it would not be hard to do so in future versions.
Pros:
-
Takes in no parameters so user will make minimal mistakes.
-
Avoid complications between unmatched name and person.
-
Easy to implement.
Cons:
-
User will have to scroll through the person list if it is very long to find a specific name. .Activity Diagram of the overallRank Command image::overallRank_activity.png[]
4.3.6. Finding competition feature
The user can filter the competitions in the system by keywords contained in the fields of the competitions.
Format: findCompetition [KEYWORD 1] … [KEYWORD N]
Example:
findCompetition NUS Open 2019
Pros:
-
Allows for user the flexibility of specifying multiple keywords allowing them to change the search scope easily.
-
Easy to implement.
Cons:
-
User will have to scroll through the filtered competition list if the keywords are contained by many competitions in the system.
4.3.7. Finding participation feature
The user can filter the participations in the system by keywords contained in the competition name or the person name of the participation.
Format: findParticipation [KEYWORD 1] … [KEYWORD N]
Example:
findParticipation NUS Axel
Pros:
-
Allows for user the flexibility of specifying multiple keywords allowing them to change the search scope easily.
-
Easy to implement.
Cons:
-
User will have to scroll through the filtered participation list if the keywords are contained by many participations in the system.
5. Documentation
Refer to the guide here.
6. Testing
Refer to the guide here.
7. Dev Ops
Refer to the guide here.
Appendix A: Product Scope
Target user profile:
-
organizes small to medium sized powerlifting competitions
-
has a need to manage a significant number athletes during the competition
-
has a need to see the ranking of the participants of each competition
-
prefer desktop applications over other types
-
can type fast
-
prefers typing over mouse input
-
is reasonably comfortable using CLI apps
Value proposition: manage powerlifting competitions faster than a typical mouse/GUI driven app
Appendix B: User Stories
Priorities: High (must have) - * * *
, Medium (nice to have) - * *
, Low (unlikely to have) - *
Priority | As a … | I want to … | So that I can… |
---|---|---|---|
|
new user |
see usage instructions |
refer to instructions when I forget how to use the App |
|
event organizer |
create a new competition |
start and organize a new competition |
|
event organizer |
sort athletes according to their attempted weights for different lifting events |
adjust the weight on stage call for the next athlete to come and attempt their lift |
|
event organizer |
find which athletes are currently in the lead (individual lifts and aggregate score) |
so that I can let the competitors know who is in the lead for their resepective weight classes and let them calculate what they need to do to win the competition |
|
event organizer |
the relative position of an athlete as compared to other athletes in their weight class |
see which athletes are in the same competition |
|
event organizer |
create participation between a person and a competition |
so as to know the participants for the respective competitions |
|
event organizer |
update an athlete’s score after a successful lift |
so that the ranking of the athletes can be updated |
|
event organizer |
edit an athlete’s name |
update the athlete’s name in case the athletes have change their names or they were inputted incorrectly previously |
|
event organizer |
record when a lifter fails/succeed in his/her lift |
update the athlete’s score and ranking accordingly and to keep a record for how each athlete’s score was derived |
|
user |
hide private contact details by default |
minimize chance of someone else seeing them by accident |
|
event organizer |
find which club/country an athlete is affiliated with |
so that I know which countries/clubs can be ranked across the various weight classess |
|
user with many persons in the system |
sort persons/competitions/participations by some field |
locate an entity easily |
Appendix C: Use Cases
(For all use cases below, the System is the Powerlifting Competition Competitor
and the Actor is the user
, unless specified otherwise)
C.1. Out of competition mode
Use case: UC1 - View my competition list
MSS
-
User requests to list all competitions in the system.
-
System shows a list of competitions held based on the files in the folder.
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
Use case: UC2 - Add a new competition
MSS
-
User requests for a new powerlifting competition to be added.
-
User inputs the initial competition data (e.g. name, start and end dates) to be inputted.
-
System adds the new competition to the user’s competition list.
-
System shows a success message.
Use case ends.
Extensions
-
2a. Competition data is invalid.
-
2a1. System shows an error message.
Use case resume at step 2.
-
-
2b. The competition name has already been used in user’s competition list.
-
2b1. System tells user that the competition is already in his competition list.
Use case ends.
-
Use case: UC3 - Delete a competition
MSS
-
User obtains a list of competitions by listing (UC1)
-
User requests for a powerlifting competition to be deleted.
-
System deletes the competition from the user’s competition list.
-
System shows a success message.
Use case ends.
Extensions
-
2a. User gives an invalid index.
-
2a1. System shows an error message.
Use case resume at step 2.
-
Use case: UC4 - Find competitions
MSS
-
User performs a search with some keywords.
-
System lists competitions that have fields containing those keywords.
Use case ends.
Extensions
-
2a. System does not find any competitions containing fields with those keywords.
-
2a1. System shows an empty list.
-
Use case: UC5 - Edit a specific competition
MSS
Extensions
-
2a. User gives invalid data.
-
2a1. System shows an error message.
Use case resumes at step 2.
-
Use case: UC6 - Enter competition mode for a particular competition
MSS
-
User requests to enter competition mode for a particular competition by entering the competition name.
-
System enters competition mode for a particular competition.
Use case ends.
Extensions
-
2a. User gives an invalid name or the competition name does not exist in the system.
-
2a1. System shows an error message.
Use case resume at step 2.
-
Use case: UC7 - View list of people
MSS
-
User requests to list all people in the system.
-
Powerlifting Competition Coordinator shows a list of all people in the system.
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
Use case: UC8 - Find people
MSS
-
User performs a search with some keywords.
-
System lists people that have fields containing those keywords.
Use case ends.
Extensions
-
2a. System does not find any people containing fields with those keywords.
-
2a1. System shows an empty list.
-
Use case: UC9 - Add a person to the system
MSS
-
User requests for a person to be added to the system.
-
User inputs person data.
-
System adds the new person to the system’s list of people.
-
System shows a success message.
Use case ends.
Extensions
-
2a. Person data is invalid.
-
2a1. System shows an error message.
Use case resume at step 2.
-
-
2b. The person is already in the system’s list of people.
-
2b1. System tells user that the person is already in the system’s list of people.
Use case ends.
-
Use case: UC10 - Edit a specific person
MSS
Extensions
-
2a. User gives invalid data.
-
2a1. System shows an error message.
Use case resumes at step 2.
-
Use case: UC11 - Delete a specific person
MSS
Extensions
-
2a. User gives an invalid index.
-
2a1. System shows an error message.
Use case resume at step 2.
-
Use case: UC12 - View my participation list
MSS
-
User requests to list all participants.
-
System shows a list of all participants.
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
Use case: UC12 - Find participations
MSS
-
User performs a search with some keywords.
-
System lists participations that have with certain fields containing those keywords.
Use case ends.
Extensions
-
2a. System does not find any participations containing fields with those keywords.
-
2a1. System shows an empty list.
-
Use case: UC13 - Edit a specific participation (Available in v2.0)
MSS
Extensions
-
2a. User gives invalid data.
-
2a1. System shows an error message.
Use case resumes at step 2.
-
Use case: UC14 - Add a new participation
MSS
-
User requests for a new participation to be added.
-
User inputs the initial participation data (e.g. person and competition name) to be inputted.
-
System adds the new participation to the user’s participation list.
-
System shows a success message.
Use case ends.
Extensions
-
2a. Participation data is invalid (e.g. Competition or person with inputted name does not exist in system).
-
2a1. System shows an error message.
Use case resume at step 2.
-
-
2b. A participation with the same person and competition has already been used in user’s participation list.
-
2b1. System tells user that the participation is already in his participation list.
Use case ends.
-
Use case: UC15 - Delete a specific participation
MSS
Extensions
-
2a. User gives an invalid index.
-
2a1. System shows an error message.
Use case resume at step 2.
-
Use case: UC16 - Overall ranking
MSS
-
User requests for people to be ranked based on the number of wins (first place finishes) they have across the competitions in the system.
-
System shows success message.
Use case ends.
C.2. In competition mode
Use case: UC17 - Get a rank of a participation
MSS 1. User requests for the ranking of a participation in the competition that is currently being run in the session. 2. System gives ranking of the participation as well as additional performance related details.
+ Use case ends.
Extensions
-
2a. System does not find any participations any person with the inputted name.
-
2a1. System shows an error.
-
Use case ends.
Use case: UC18 - Get a list of participations based on their score by some ranking method
MSS
-
User requests for participations in the current competition in-session to be ranked based on their score given by some ranking method.
-
System shows the participations sorted by the ranking method with their scores.
-
System shows success message.
Use case ends.
Use case: UC19 - Call for next participant in lifting order
MSS
-
User requests for next athlete to attempt lift.
-
System shows athlete that is lifting next.
-
User updates system after athlete attempts lift.
-
System shows success message.
Use case ends.
Extensions
-
2a. No more participants in lifting order.
Use case ends.
Use case: UC20 - Exit competition
MSS
-
User requests to exit competition mode.
-
System exits competition mode.
Use case ends.
C.2.1. Use case: UC21 - Finalize competition
MSS
-
User requests to finalize competition data.
-
System finalizes competition and prevents any further updating of the competition data.
Use case ends.
Extensions
-
2a. There are still participants that have not finished their lifts
Use case ends.
{More to be added in v2.0}
Appendix D: Non Functional Requirements
-
Should work on any mainstream OS as long as it has Java
1.8.0_60
or higher installed. -
Should work on both 32-bit and 64-bit environments.
-
Should come with automated unit tests and open source code.
-
Should come with a user guide and a developer guide.
-
Should favor DOS style commands over Unix-style commands.
-
Should be intuitive such that a new user can learn to search and organize a powerlifting competition within 10 minutes.
-
A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse. {More to be added}
Appendix F: Instructions for Manual Testing (To Do)
Given below are instructions to test the app manually.
These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing. |
F.1. Launch and Shutdown
-
Initial launch
-
Download the jar file and copy into an empty folder
-
Double-click the jar file
Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
-
-
Saving window preferences
-
Resize the window to an optimum size. Move the window to a different location. Close the window.
-
Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained.
-
F.2. Deleting a person
-
Deleting a person while all persons are listed
-
Prerequisites: List all persons using the
list
command. Multiple persons in the list. -
Test case:
delete 1
Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated. -
Test case:
delete 0
Expected: No person is deleted. Error details shown in the status message. Status bar remains the same. -
Other incorrect delete commands to try:
delete
,delete x
(where x is larger than the list size) {give more}
Expected: Similar to previous.
-