1. PROJECT: Budget Buddy
This portfolio serves to provide a breakdown of what I have contributed as a student in the software engineering project, Budget Buddy.
2. About Budget Buddy
Budget Buddy is a desktop-based expense tracking application made for students, NUS School of Computing students in particular, to keep track of and manage their finances better. The user interacts with it using a Command Line Interface (CLI), and it has a Graphical User Interface (GUI) created with JavaFX. The application is written in Java, and has about 15 kLoC.
This is a software engineering project in which groups are tasked to enhance or morph a simple CLI-based address book application. The end result is a expense tracking application with focus on programmers, to make customisation that much easier.
Budget Buddy is able to maintain separate accounts, handle a multitude of transactions within an account, and even track any loans that the user might have made. Rules can be added to make repetitive tasks automated, and scripts can even allow the user to create mass changes to data in their own way by themselves.
3. Project Role
My task in this project is the Rule Engine feature, which allows for the automation in the application, executing certain tasks automatically upon the addition of a new transaction. The following sections will elaborate on this feature, which includes the additions I have made to both the user and developer guides.
Take note of the following formatting used in the rest of this portfolio.
|
Monospace text like this indicates that this is a command word that can be entered as part of a command to be executed by the application. |
filename.txt |
Bold italicized text like this indicates that this is a filename that can be found within the application. |
|
Bold monospace text like this indicates that this is a component that can be found within the application. |
4. Summary of contributions
This section provides an overview of my contribution to this application. |
4.1. Major enhancement:
Added the ability to add/list/edit/remove rules, as well as executing them.
-
What it does: Allows the user to define a set of rules in the rule engine which will be executed by the rule engine upon adding/editing a transaction. A rule may carry out an action depending on whether the transaction satisfies the rule’s condition, or "predicate".
-
Justification: This feature improves the application significantly because for day-to-day transactions, there may be many repetitions in what the user types. The app can therefore help users save time by automating such repetitive processes, or even more, depending on how the user uses it.
-
Highlights: Setting up rules was a challenge, as it created an additional source of "logic" besides commands, which required a new structure from the bottom up. A method to process rules had to be made, and considering that both expressions and scripts can be used for rules, a unified way to process them was required.
4.2. Minor enhancement:
Set up panel management within the GUI.
-
What it does: Allow easy switching between panels within the same frame.
-
Highlights: Different panels were required based on the currently active tab, hence managing panels properly allowed for switching between them to be much easier.
4.3. Code contributed:
I have contributed over 30 pull requests to the repository as of 11 November 2019.
All of my contributions can be found here: [RepoSense Analysis]
4.4. Other contributions:
-
GUI Enhancements:
-
Bug fixes:
-
Fix bugs noted during PE dry run: Pull request #153
-
-
Documentation:
-
Contributed to the User Guide and Developer Guide. See Section 5 and 6 below for detailed breakdown.
-
-
Community:
5. Contributions to the User Guide
This section shows what I have contributed to the User Guide. They showcase my ability to write documentation targeting end-users. |
You can refer to the full User Guide here.
5.1. Overview of Contributions
Below is an overview of my contributions to the User Guide.
5.1.1. Improve user experience
I added multiple sections and introductory paragraphs, which include the Introduction, Quick Start, Getting Started, Features, and FAQ, that provide clarification and support in usage for the users who are using the application for the first time, or need help with troubleshooting.
5.1.2. Add main content into the User Guide
I wrote detailed sections about the usage of commands that are in the Budget Buddy application, to guide users in the format and specifications required for those commands. An extract from the User Guide that were written by me is shown in section 5.2 below.
5.2. Automating with rules: rule
Introducing the Rule Engine. A way for you to automate certain actions based on a certain predicate. Spend less time typing repetitive commands, and spend more time keeping track of your expenses!
Rules have the following structure: if "predicate" is true, then perform "action". By creating a predicate which defines the condition you set, you can perform any action you create whenever a transaction is added/edited, if the transaction satisfies that condition.
All rules in the Rule Engine will be executed on a transaction, when:
-
It is a new transaction and has been successfully added into an account. OR
-
It is an existing transaction and has been successfully edited.
The picture above shows a transaction added with the command:
txn dn/out x/200 d/Treat friends to buffet food!
As you can see, two of the rules from the example list of rules above were applied on the transaction, and added categories to it.
5.2.1. Add a new rule: rule add
Adds a new rule to the rule engine. Both the predicate and action have to be specified. A rule can be formed using either expressions or scripts, or both.
Format: rule add p/<expression|script name> a/<expression|script name>
5.2.2. Swap two rules: rule swap
Ths will affect the execution order of the rules. Rules will be executed from the top of the list downwards. |
Swaps the position of two specified rules in the Rule Engine.
Format: rule swap <rule 1 ID> <rule 2 ID>
Examples:
-
rule swap 2 4
Swaps the ordering of the 2nd rule and the 4th rule.
6. Contributions to the Developer Guide
This section shows what I have contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project. |
You can refer to the full Developer Guide here.
6.1. Overview of Contributions
Below is an overview of my contributions to the Developer Guide.
6.1.1. Add main content into the Developer Guide
I wrote detailed sections about the implementations of functionality in the Budget Buddy application, drawn UML diagrams, and documented some use cases for the Developer Guide. A few extracts of the Developer Guide that were written by me are shown in section 6.2 and 6.3 below.
6.2. Rule Management Feature
The Rules feature exists as an integration onto the Transaction system. It makes use of syntax processing, together with scripts to provide an automation solution to repetitive tasks when adding transactions.
Rules are defined with a pair of predicate and action, where an action is performed given that the predicate returns true. This predicate-action split allows us to decouple testing from performing, which helps to increase reusability of individual predicates and actions.
6.2.1. Implementation
Basic attributes and operators are exposed to provide users a way of writing simple
tests on transactions without having to manually check and make changes. Storing rules
works similarly to LoansManager, where individual rules are stored in a
RuleManager
which manages all CRUD operations.
All rules are stored in a JSON file when added, formatted to be retrieved and parsed by the application when relaunched.
The following class diagram illustrates the structure of the Rule
Model component.
The rest of the Script and Model components have been omitted to give focus on the Rule model component.
|
As mentioned above, rules are defined as a pair of predicate and action, which as seen in the above diagram, is divided into
the two abstract classes RulePredicate
and RuleAction
. These two classes are abstract due to two implementation
types, either script or expression. Their concrete classes are PredicateExpression
and ActionExpression
for expressions and PredicateScript
and ActionScript
for scripts respectively.
6.3. Rule Execution Feature
The structure of rules were separated from the logic of rule execution to maintain the separation of concerns between the
Model
and Logic
components.
Rule execution is hooked into the evaluation of adding or editing a Transaction
. This means that for every new transaction,
all rules within the Rule Engine will be executed on that transaction. The same can be said for modifying a transaction.
The implementation of the Rule execution is elaborated on below.
6.3.1. Implementation
The RuleEngine
is a static class used for interfacing with all the rule processings functionality.
Two executable classes are used in the execution of a rule, Testable
and Performable
.
A Testable
represents the executable form of a RulePredicate
, which may be either an expression or a script.
Correspondingly, a Performable
represents the executable form of a RuleAction
, which may also be either an
expression or a script.
Before executing the existing rules, the index of the transaction and the account that the transaction belongs to are
supplied to the RuleEngine
through the RuleEngine#executeRules
method. This allows for the retrieval of the transaction
when a rule is executed against it.
When a rule is executed, this is firstly represented as the execution of the Testable#test
method on the given transaction.
If the test passes, the predicate is true, and therefore the action is performed. This is represented as the execution of
the Performable#perform
method on the given transaction.
The following sequence diagram shows the interaction between the RuleEngine
and the different objects involved in the
execution of the rules on a transaction:
Shown above is a sequence diagram which takes place during the execution of the TransactionAddCommand
,
after the new transaction has already been added. The RuleEngine
takes over, and retrieves the relevant handlers from
Model
.
Thereafter, the list of rules is retrieved from the RuleManager
. The RuleEngine
iterates through the list,
using the RulePredicate
and RuleAction
of each rule to create the required Testable
s for testing on the
transaction, as well as the Performable
s for performing the action.
The following activity diagram shows in greater detail the workflow of executing rules.
The activity diagram above has a slightly different context as the sequence diagram, to show a separate use case. In this diagram, instead of a new transaction that is added, we have a transaction that is edited. Both types of commands do not affect the workflow of rule execution.
In this diagram, the generation of a Testable
and Performable
is shown in greater detail.
Testable
is an interface which, like RulePredicate
, have its implementations split into expressions and scripts,
namely TestableExpression
and TestableScript
.
Similarly, Performable
is an interface which, like RuleAction
, have its implementations split into expressions
and scripts, namely PerformableExpression
and PerformableScript
.
Expressions are generated by the RuleEngine
when either the RulePredicate
or RuleAction
are of the expression type.
The RuleEngine
will retrieve the correct expression constructor from an internal hash map based on the Operator
,
and create the expression using the given attribute and/or value.
Scripts, on the other hand, are generated by the RuleEngine
when either the RulePredicate
or RuleAction
are of
the script type. The RuleEngine
will generate the corresponding Testable
or Performable
by first retrieving
the script from the ScriptLibrary
based on its ScriptName
. Following that, a TestableScript
or PerformableScript
is instantiated with a function ScriptEvaluator
, which evaluates the script given the transaction and account. This
function is then called when Testable#test
or Performable#perform
is executed.
6.3.2. Design Considerations
Aspect: Duplication of predicates and actions in model and logic
-
Alternative 1 (current choice): Both predicates and actions have their corresponding versions in both model and logic.
-
Pros: Able to split the logic flow and execution code from the data in model.
-
Cons: Seemingly duplicate classes, such as
PredicateExpression
andTestableExpression
, which increases the number of classes.
-
-
Alternative 2: All execution data and logic is stored in the rule model rather than logic.
-
Pros: Reduce class duplication, less confusion.
-
Cons:
Model
andLogic
will have unnecessary coupling which reduces testability and makes maintenance and integration harder.
-