Skip to content

Commit

Permalink
Merge pull request #107 from CSSE6400/86
Browse files Browse the repository at this point in the history
maintainability docs
  • Loading branch information
86LAK authored May 26, 2024
2 parents 81046e4 + a6b4df0 commit 758cbb1
Showing 1 changed file with 7 additions and 9 deletions.
16 changes: 7 additions & 9 deletions report/REPORT.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,17 @@ The purpose of this report is to document the various design decision made throu

Throughout the project there were required changes compared to what was outlined in the proposal due to limitations in time as well as to better adhere to the quality attributes we aimed to achieve.

#### Accounts
### Accounts

In the project proposal it was outlined that the users should be able to create an account and register their university affiliation. However, due to time constraints we were forced to cut out the university affiliation and centre the project around University of Queensland students.

The team had also realised that the allowing users to sign up would require us to handle the variety of security risks it would introduce such as storing user login data. Therefore, we decided to use AUTH0 to handle the login using external accounts such as Gmail or GitHub. This however, had the unintended affect that it removed our ability to allow users to update the account information or profile picture as that it was handled by AUTH0. The decision to use AUTH0 was made after careful consideration of its security practices and its effect on the project.

#### Courses
### Courses

The project proposal also outlined that users should be able to create new courses and update that information. Due to the time restrictions and complexity this functionality would have caused we very quickly decided to not include this feature in our MVP. This decision also led to us only adding a few courses to our website to demonstrate the rest of the project’s functionality. This cutting of the scope allowed us to refocus our efforts on enabling the user to filter/ search courses and pin their favourite courses. We also used the extra resources to expand the scope and allow users to rate a course.

#### Exams
### Exams

We weren't able to fully implement the exam functionality. We were able have to implement functionality to allow users to add new questions to an exam. (TODO Maybe not the case anymore)

Expand All @@ -79,11 +79,11 @@ There were also some downsides that were discovered when evaluating if the micro

The other architecture that was considered was a Monolithic Architecture. The simplicity of development in this architecture was its main intriguing aspect, as it would have enabled us to quickly develop the project which was very important in our short timeframe. The second drawing point was ease of deployment, as the monolithic app would of been contained in one container there deployment and maintaining of the app would have been easy. Finally, a monolith would have made system and integration testing easier as the end-to-end tests would have run a single application which also leads to easier debugging.

However, there were a few downsides of using the Monolithic architecture which led us to not use it. Primarily, the larger our application grew the more complex it would become to understand. Adding or upgrading functionality would be become difficult as it might cause unexpected side effects. The coupling of services into a monolith would have led to greater dependency between different services making identifying the cause of issues much higher. Finally, to scale our application it would require the application replicated on multiple servers which would have increased costs compared to other architectures. Due to all these reasons we came to the conclusion that the Monolithic Architecture would not be suitable for our project as it does not aid in trying to achieve the quality attributes we had set.
However, there were a few downsides of using the Monolithic architecture which led us to not use it. Primarily, the larger our application grew the more complex it would become to understand. Adding or upgrading functionality would be become difficult as it might cause unexpected side effects. The coupling of services into a monolith would have led to greater dependency between different services making identifying the cause of issues much higher. Finally, to scale our application it would require the application replicated on multiple servers which would have increased costs compared to other architectures. Due to all these reasons we came to the conclusion that the Monolithic Architecture would not be suitable for our project as it does not aid in trying to achieve the quality attributes we had set.

## Architecture

To enable UniBasement to meet the described architecturally significant requirements, a layered architecture comprised of four layers was implemented. The highest layer was the Presentation Layer, which was comprised of our front-end, built with Next.js using Tailwind. These technologies were chosen as they are industry standard which enables easier contribution. Components within the front-end were designed to be generic and extensible where possible whilst maintaining a maximum of 300 lines to minimise complexity. Unit tests were implemented through the integration tests to ensure that functionality was as expected. The business layer was implemented to handle the application logic, business rules, and objectives; it handles the logic and enables the functionality of the application. This was implemented within Node.js and tested through Jest which are both industry standard. The Persistence Layer manages requests and interacts with the database (DB). Through the use of TypeORM, the developer experience is enhanced whilst adding a protective barrier for the DB. By abstracting the database interactions, the DB technology is interchangerable and it also streamlines development. The DB Layer was implemented via PostgreSQL as it’s an industry-standard relational database management system (RDBMS). PostgreSQL ensures data security and provides robust features for managing data.
To enable UniBasement to meet the described architecturally significant requirements, a layered architecture comprised of four layers was implemented. The highest layer was the Presentation Layer, which was comprised of our front-end, built with Next.js using Tailwind. These technologies were chosen as they are industry standard which enables easier contribution. Components within the front-end were designed to be generic and extensible where possible whilst maintaining a maximum of 300 lines to minimise complexity. Unit tests were implemented through the integration tests to ensure that functionality was as expected. The business layer was implemented to handle the application logic, business rules, and objectives; it handles the logic and enables the functionality of the application. This was implemented within Node.js and tested through Jest which are both industry standard. The Persistence Layer manages requests and interacts with the database (DB). Through the use of TypeORM, the developer experience is enhanced whilst adding a protective barrier for the DB. By abstracting the database interactions, the DB technology is interchangerable and it also streamlines development. The DB Layer was implemented via PostgreSQL as it’s an industry-standard relational database management system (RDBMS). PostgreSQL ensures data security and provides robust features for managing data.

![UniBasement Layered Architecture Implementation](./Images/Architecture.png)

Expand All @@ -101,8 +101,6 @@ To accurate critique the developed architecture for UniBasement, -->

- layered architecture doesn't have the best maintainability because of the how layer being grouped together



## Evaluation

### Testing
Expand All @@ -129,11 +127,11 @@ The repo features fully functioning integration tests which is capable of testin

#### Availability

In order to enhance the availability of our software, we utilized tools from Amazon Web Services (AWS) and leveraged the benefits of a Layered Architecture. To manage website traffic, we implemented a load balancer to improve fault tolerance. This load balancer can automatically detect server issues and reroute traffic to operational servers. Furthermore, we used Terraform to configure our application to dynamically scale resources based on load, effectively handling peak usage times. The Layered Architecture plays a crucial role in fault isolation, allowing us to address and resolve issues in one layer without disrupting the others. To ensure the robustness of our website, we conducted rigorous testing. This approach ensures that any potential issues are identified and rectified promptly, thereby maintaining the website’s availability. Finally, we deployed the website over a 1 hour period and simulated a expected load and the website did not run into issues or downtime. To test the availability of our system we ran simulated tests were certain containers were killed. We tested the systems availability and ability to recover from this and still maintain functionality. From our tests that we conducted where we deliberately killed both the frontend and backend containers we found that the system was able to recover and maintain functionality. The test plan showing the steps taken and the result are documented and can be found here [documented](../docs/MANUAL.md).
In order to enhance the availability of our software, we utilized tools from Amazon Web Services (AWS) and leveraged the benefits of a Layered Architecture. To manage website traffic, we implemented a load balancer to improve fault tolerance. This load balancer can automatically detect server issues and reroute traffic to operational servers. Furthermore, we used Terraform to configure our application to dynamically scale resources based on load, effectively handling peak usage times. Using autoscaling groups we ensure that a minimum of 1 service is always running for both the frontend and backend. If an error were to occur and a service to go down, the autoscaling group can recover the service. The Layered Architecture plays a crucial role in fault isolation, allowing us to address and resolve issues in one layer without disrupting the others. To ensure the robustness of our website, we conducted rigorous testing. This approach ensures that any potential issues are identified and rectified promptly, thereby maintaining the website’s availability. Finally, we deployed the website over a 1 hour period and simulated a expected load and the website did not run into issues or downtime. To test the availability of our system we ran simulated tests were certain containers were killed. We tested the systems availability and ability to recover from this and still maintain functionality. From our tests that we conducted where we deliberately killed both the frontend and backend containers we found that the system was able to recover and maintain functionality. The test plan showing the steps taken and the result are documented and can be found here [documented](../docs/MANUAL.md).

#### Reliability

There were numerous techniques employed to achieve the high level of reliability that we had set at project conception. In the project proposal it was outlined to achieve the necessary level of reliability, the project should have unit tests that thoroughly covers the core functionality of the system. These tests should ensure that the system maintains expected behaviour. We used test driven development to implement the unit and integration tests that cover the entire functionality of our application and previously mentioned in the testing section. These tests are then used in a GitHub workflow to ensure that every time a code change is pushed to main the tests run to ensure the core functionality works before the code reaches main.
There were numerous techniques employed to achieve the high level of reliability that we had set at project conception. In the project proposal it was outlined to achieve the necessary level of reliability, the project should have unit tests that thoroughly covers the core functionality of the system. These tests should ensure that the system maintains expected behaviour. We used test driven development to implement the unit and integration tests that cover the entire functionality of our application and previously mentioned in the testing section. These tests are then used in a GitHub workflow to ensure that every time a code change is pushed to main the tests run to ensure the core functionality works before the code reaches main. The availability of dev tools for deploy, teardown, redeployment and tests enhances the developer experience. The workflow for tests can be run on any branch and they are also able to be run locally or through the GitHub Actions. For more information about running / adding / using tests please visit [documented](../docs/TESTS.md).

Secondly, by deploying our application to Amazon Web Services, we remove the necessity to ensure the webservers running our application are working correctly. Through the shared responsibility model AWS is responsible for the infrastructure such as the hardware, software and networking that run AWS Cloud services. We then using terraform ensure the containers we deploy are reliable on AWS.

Expand Down

0 comments on commit 758cbb1

Please sign in to comment.