Skip to content

Commit

Permalink
Update REPORT.md
Browse files Browse the repository at this point in the history
  • Loading branch information
vilnor committed Jun 2, 2024
1 parent ca00f5b commit 0f7b90e
Showing 1 changed file with 14 additions and 13 deletions.
27 changes: 14 additions & 13 deletions report/REPORT.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,31 +49,32 @@ This architecture additionally affected the design decisions regarding the imple
![UniBasement System Context Diagram](../model/images/structurizr-SystemContext-001.png)
![UniBasement System Context Diagram](../model/images/structurizr-Container-001.png)

## Critique and Tradeoffs
## Critique & Tradeoffs

When analysing the choices made throughout the project some sacrifices / tradeoffs had to be made. To accurately critique UniBasement's architecturally significant decisions, it is important to consider both functional and non-functional requirements. Each of these will be assessed individually.
## Trade-Offs
When analysing the choices made throughout the project some sacrifices and tradeoffs had to be made. To accurately critique UniBasement's architecturally significant decisions, it is important to consider both functional and non-functional requirements. Each of these will be assessed individually.

Through the choice of the layered architecture, it detrimentally affected the scalability and integration testing. As UniBasement's implementation of the layered architecture relied on a monolithic backend, it naturally raises concerns regarding the scalability. When designing UniBasement, one of the primary concerns was the viability for the minimum viable product (MVP). Given that the deadline for the task was the limiting factor, it was important for the architecture to be simple, this came at the cost of scalability. A micro-services architecture could have scaled much more effective as opposed to the monolithic backend that UniBasement uses. This naturally will affect the scalability and the reliability of the application. Another aspect of UniBasement that was affected by the architecture choice was the integration testing. Due to the multiple layers of the architecture, it increased the complexity of the integration tests created. This added additional complexity and time required to complete the integration test. Whilst this was not a major concern, as one of the primary objectives was to deliver a product within a short period of time, this was a concern that was considered whilst determining the architecture UniBasement used. A layered architecture had two identified specific tradeoffs, scalability and affect to integration tests for UniBasement.
### Functional Requirements

## Critique
Overall the project has successfully met all functionality described in the project proposal when considering the changes made in the [Changes](#changes) section. This includes the functionality to create courses, exams, questions, answers, upvote and downvote. To allow for strict permissions on who can create a course, it was decided to implement auth0 to handle user authentication ([ADR001](../model/adrs/ADR001_AUTHENTICATION.md)) and implement user roles ([ADR005](../model/adrs/ADR005_USER_ROLES.md)). The implementation of these two features works together to ensure the security of the system and to ensure only authorised users can make changes. This also allows us to enforce allowing only the user who created content to edit it, preventing malicious actors. The use of user roles also allows us to enforce only administrators having extended permissions to create courses and exams. The implementation of these features was successful which met and exceeded the requirements set out in the project proposal.

To accurately critique UniBasement's architectural decisions, it is important to consider both functional and non-functional requirements. Each of these will be assessed individually.
Using auth0 had its tradeoffs, however. Due to its integration into the frontend it increased the complexity of both running the frontend locally and the e2e tests. Because of this, a developer needs an auth0 tenant setup and running so that they can develop locally. This is a tradeoff as it restricts developers to have a stable internet connection while developing locally, and also depends on an external service being available. It also increased the complexity of the e2e tests, as the majority of our system requires the user to be logged in. To get around this we implemented a test account in a development auth0 tenant that the playwright system could login with to ensure proper e2e tests were still conducted. Although implementing user authentication via auth0 had these tradeoffs, it does greatly increase the security of our system and hence was worth implementing.

### Functional Requirements
Users have the ability to add both text and images to a question and answer. This raises the concern of inappropriate, malicious, or illegal text or images. This was not determined to be within the scope of the minimum viable product and would have added unnecessary complexity to the UniBasement prototype. It was therefore not implemented, however would be a consideration for any future work of the project. One other aspect not implemented was Universities other than UQ. This was also determined to be out of the scope of the MVP, as we did not have access to any courses or examinable content from other universities. However, implementations of other universities was considered in the database structure with support for assigning courses to a university. This would allow for easy implementation of other universities in the future.

Overall our architecture allowed us to deliver all the functionality of the MVP and exceed it in some areas. The choice of a layered architecture allowed us to easily implement this functionality rapidly and with minimal complexity.

Overall the project has successfully met all functionality described in the project proposal excluding the changes made in the [Changes](#changes) section. This includes the functionality to create courses, exams, questions, answers, upvote and downvote. To allow for strict permissions on who can create a course, it was decided to implement auth0 to handle user authentication [ADR001](../model/adrs/ADR001_AUTHENTICATION.md) and implement user roles [ADR005](../model/adrs/ADR005_USER_ROLES.md). The implementation of these two features works together to ensure the security of the system and to ensure only authorised users can make changes. This is important as it allows us to enforce only the creating user (for a comment / question / upvote / downvote) can edit or delete their own content. The use of user roles allows us to enforce only administrators have extended permissions to create courses and exams. The implementation of these features was successful which met and exceeded the requirements set out in the project proposal. Using auth0 had its tradeoffs however, due to its integration into the frontend it increased the complexity of both running the frontend locally and the end to end tests. Due to its integration a developer needs a auth0 tenant setup and running so that they can develop locally. This is a tradeoff as it restricts developers to have a stable internet connection while developing locally. It also increased the complexity of the end to end tests, as the majority of our system requires the user to be logged in. To get around this we implemented a test account that the playwright system could login with to ensure proper end to end tests were still conducted. Although implementing user authentication via auth0 had these tradeoffs, it greatly increases the security of our system and hence was worth implementing. Overall our architecture allowed us to deliver all the functionality of the MVP and exceed it in some areas. The choice of a layered architecture allowed us to easily implement this functionality with minimal complexity.
The functional requirements of UniBasement were fully met, with only selecting universities other than UQ not added. All functionality was implemented as outlined within the Proposal. This included the implementation of creating courses, exams, questions, and answers. Creating courses and exams was limited to admin users to prevent bad actors potentially defacing of harm UniBasement (i.e making hundreds of false courses would degrade search performance). Users have the ability to add both text and images to a question and answer. This raises the concern of inappropriate, malicious, or illegal text or images. This was not determined to be within the scope of the minimum viable product and would have added unnecessary complexity to the UniBasement prototype. One other aspect not implemented was Universities other than UQ. This was due to this being determined out of the scope of the minimum viable product, additionally, we did not have access to any courses or examinable content or other university emails. Implementations of other universities was considered in the database structure. The functional requirements were conclusively met, with text and image validation not implemented, and selecting universities other than UQ not added.

### Non-Functional Requirements

During the early stages of development we were highly coupled with Postgres as our backend service relied on specific Postgres features. After our initial backend service was developed we quickly identified this as impacting the maintainability and reliability of our system. To reduce our reliance on a specific implementation of SQL we decided to use an ORM as a persistence layer between the database and the backend so that we could abstract out SQL queries. This change and implementation is covered in [ADR002](../model/adrs/ADR002_ORM.md). By introducing TypeORM we added a persistence layer into our architecture. This enabled us to be less reliant on Postgres and increase our maintainability and reliability. Alongside this change we also decided to make our backend codebase more maintainable.
During the early stages of development we were highly coupled with Postgres, as our backend service relied on specific Postgres features. After our initial backend service was developed we quickly identified this as impacting the maintainability and reliability of our system. To reduce our reliance on a specific implementation of SQL we decided to use an ORM as a persistence layer between the database and the backend so that we could abstract out SQL queries. This change and implementation is covered in [ADR002](../model/adrs/ADR002_ORM.md). By introducing TypeORM we added a persistence layer into our architecture. This enabled us to be less reliant on Postgres and increase our maintainability and reliability. Alongside this change we also decided to make our backend codebase more maintainable.

To do so, we introduced a change from a single file for all routes, to multiple files for each route category. This was a change to our implementation of the architecture, and it increased the maintainability of our system. More detail can be found in [ADR003](../model/adrs/ADR003_ROUTES.md). This improvement was made to allow developers to easily find the functionality they are looking for as they are all grouped together in logical files. It also meant that any changes to the API endpoints themselves in Express were easier to implement since the route logic is separated out from where the Express router is created.

Another change made during the development of our system was the change from a single file for all routes, to multiple files for each route. This is a change to our implementation of the architecture and it increases the maintainability of our system. This change is covered in [ADR003](../model/adrs/ADR003_ROUTES.md). This improvement was made to allow developers to easily find the functionality they are looking for as they are all grouped together in their own file. LIV TO INSERT SENTENCE HERE ABOTU SOME EXPRESS HSHIT!?!!?
As part of our reliability quality attribute we decided to change our integration tests. Originally the integration tests would send requests to the backend service and just confirmed the received HTTP response code and body were as expected. To increase the reliability of our project it was decided to implement [ADR004](../model/adrs/ADR004_INTEGRATION_TESTS_WITH_DB.md). ADDR004 covers the change to connect the test container directly to the database. By doing this we were able to verify the changes were indeed made to the DB and to validate what the backend service was doing. This greatly increased the reliability of our project.

As part of our reliability quality attribute we decided to change our integration tests. Originally the integration tests would send requests to the backend service and just confirmed the received HTTP response code and body. To increase the reliability of our project it was decided to implement [ADR004](../model/adrs/ADR004_INTEGRATION_TESTS_WITH_DB.md). ADDR004 covers the change to connect the test container directly to the database. By doing this we were able to verify the changes were indeed made to the DB and to validate what the backend service was doing. This greatly increased the reliability of our project.
To ensure UniBasement is available, we implemented an AWS autoscaling group on both the frontend and backend which allows for the recovery of services if they go down. Also, during initial deployment testing, we noticed that if one service went down the IP address for the service would change. This resulted in the frontend and backend services no longer being connected together, since the backend API address was passed in as an environment variable to the frontend image. To fix this we implemented [ADR006](../model/adrs/ADR006_LOAD_BALANCERS.md) where a load balancer was placed between both user and frontend and between the frontend and backend service. The main change here was the implementation of a load balancer between the frontend and backend services. This allows for the frontend to not need to be recreated (to pass the backend API url) if the backend service went down. This increased the availability of our system, as the AWS autoscaling groups handle recovery of each service task and the entire system is only impacted for ~5 minutes overall while a new task is spinning up.

To ensure the availability of UniBasement many things were considered. Firstly to ensure UniBasement is available we implemented via terraform an AWS autoscaling group on both the frontend and backend, which allows for the recovery of services if they go down. During testing we noticed that if one service went down the url for the service would change. This resulted in us having a frontend service and backend service that was no longer connected together. To fix this we implemented [ADR006](../model/adrs/ADR006_LOAD_BALANCERS.md) where a load balancer was placed between both user and frontend and between the frontend and backend service. The main change here was the implementation of a load balancer between the frontend and backend services. This allows for the frontend to not need to be recreated (to pass the url to the backend) if the backend service went down. This change increases the availability of our system, as the AWS autoscaling handles recovery of each service task and the entire system is only impacted for ~5 minutes overall while the task is spinning up. This also links us into our discussion about the chosen architecture. By using a layered architecture we ensured the availability of each service independently and scaled each part independently. Tradeoff of our architecture is that it is not as scalable as a microservices architecture. However, for the size of our project and time constraints a layered architecture was more appropriate. Especially since if we split the current backend service up we would have many services doing very little. Overall our use of the layered architecture ensured the availability, maintainability and reliability of our system.
By using a layered architecture we ensured the availability of each service independently and scaled each part independently. The tradeoff for this is that it may not be as scalable as a microservices architecture. However, for the size of our project, the scope it encompassed, and the given time constraints, a layered architecture was actually more appropriate. The current backend functionality being split into many smaller services would be overkill since there is simply not enough functionality there to justify having individual services. Overall, our use of the layered architecture ensured the availability, maintainability and reliability of our system.

## Evaluation & Testing

Expand Down

0 comments on commit 0f7b90e

Please sign in to comment.