Architectural Kata Series
In the current context of software development, doing a system design or an architectural plan from scratch is reserved most of the time,to an architect or a more experienced developer/technical lead who can bring value and experience into making the best decisions. How can we handle a situation where we want to gain this experience, but maybe we need to create the context that allows us to contribute to a system in the first steps of its creation? We have two solutions: look for another more suitable context, take the lead in our professional development plan, or start exercising independently, simulating the architecting and designing phase a system.
To help with this process, there is a concept called Kata. As Wikipedia states, Kata is a Japanese word (型 or 形) meaning “form”. It refers to a detailed choreographed pattern of martial arts movements made to be practiced alone. It can also be reviewed within groups and in unison when training. This concept was also integrated into software development, first for simple coding exercises and then for architecture.
These are usually intended for groups, but we can do them independently for professional development. Don’t worry. We will take one problem at a time from Neil Ford’s site,https://nealford.com/katas/, and try to sketch a starter system design and architecture based on some precise requirements.
1st problem: Make the Grade
The problem I want us to analyze for this exercise is Make the Grade:
The system is designed to support standardized testing across public school systems for grades 3–12, accommodating over 40,000 students, 2,000 graders, and 50 administrators.
Architectural Components
To start as simple as possible, we can use this approach:
- UI that accommodates different roles and users
- Securely manage multiple-choice, short-answer, and essay tests with manual grading, score consolidation, and detailed reporting capabilities.
- Store the information
Let’s dig through more in detail these points:
1. Application Architecture
Regarding the user interface, we discuss a user-friendly design, accessible across devices for students, teachers, and administrators. The interface should be intuitive and easy to navigate. Modern web technologies like React or Angular should be suitable to ensure scalability and a dynamic user experience.
Microservices Architecture
A microservices architecture can ensure scalability and independent deployment of different system parts. For our educational testing system, the following services would be implemented:
- User Management Service: managing user profiles and authentication.
- Test Management Service: creating, storing, and retrieving tests.
- Results Consolidation Service: aggregating test scores.
- Reporting Service: generating reports on test outcomes.
- Test-Taking Service: facilitating test-taking.
- Grading Service: manually grading open-ended questions.
- Content Management Service: managing test content.
To strengthen our testing system by managing user access and smoothing traffic flow, we could introduce an API Gateway. We can speed up common requests(e.g., viewing test instructions) by storing frequently used information. It integrates with authentication services to ensure that only authorized users can access sensitive functionalities, guaranteeing the protection of student data and test integrity. An API Gateway also helps to implement rate limiting during peak periods such as exam days, preventing overload and ensuring the system remains responsive and available. This makes our testing platform more secure and quick to respond when needed.
Last but not least, using an API Gateway, we can facilitate updates and allow backend services to evolve independently without affecting the client interface.
Database Structure
Let’s start simple, when it comes to storing data, we can use a relational model to ensure data integrity, with tables for School, Students, Tests, Questions, Student Answers, Graders, and Grades, as in the model below.
But things are not always that straightforward; let’s remember that each microservice should have its dedicated database to ensure loose coupling, allowing services to be developed, deployed, and scaled independently. We can extend the discussion while keeping this in mind.
- Test Management Service: This service uses a relational database (e.g., Azure SQL Database) to manage tests, questions, and answer choices due to its structured nature and the need for complex queries.
- User Management Service: Can also utilize a relational database to handle user data, roles, and permissions, ensuring integrity and security of authentication and authorization data.
- Grading Service: Again, a relational database fits best because we need to manage submissions, grades, and feedback, requiring transactional integrity to update grades.
- Reporting Service: It might benefit from combining a relational database for storing report data and a NoSQL database (e.g., Azure Cosmos DB) for aggregating large volumes of test result data for analytics.
- Content Management Service: A NoSQL database can be used for flexibility in managing various types of content, including multimedia test materials.
Non-Functional Requirements
Non-functional requirements (NFRs) are crucial quality attributes ensuring the system meets its functional goals and delivers a robust, efficient, and user-friendly experience. NFRs impact the system’s effectiveness, customer satisfaction, and operational costs, making them essential for any software project’s success. In this discussion, we’ll cover some of the most crucial NFRs for our system.
Performance
We must consider performance to ensure fast and responsive test access, especially during peak usage times when many students simultaneously take exams. High performance prevents delays and frustration and contributes to a fair and stress-free testing environment for all participants.
To improve the performance and responsiveness of the application, the following steps can be taken:
- Deploy a Content Delivery Network (CDN) to serve static content. This will reduce the load on the application server and improve the user experience.
- Use load balancers to distribute traffic evenly across application servers. This will ensure that the application remains responsive even under heavy load.
- Use Redis Cache to implement caching for frequently accessed data, such as test questions and scores. This will reduce the database’s load and improve response times.
Availability
Another important NFR is availability. We want to avoid situations where the system is inaccessible when students are scheduled to take tests. This is especially important during designated testing windows, ensuring no student is disadvantaged by system downtime and maintaining fairness in the testing process.
Depending on how much the system will extend further, these are some strategies for making sure we have availability:
- Deploy services across multiple zones to mitigate downtime risks.
- Ensure smooth distribution of incoming traffic and failover capabilities.
- Deploy application and database instances across multiple availability zones to ensure high availability.
- Implement regular backups and a disaster recovery plan to minimize downtime in the event of a failure.
Reliability
When discussing a statewide standardized testing system, we must remember availability. It is essential to stay consistent and ensure accurate test delivery, grading, and results reporting.
Students, teachers, and administrators depend on the system during exam periods, and we need to ensure everything functions correctly without errors or downtime. Errors and downtime can impact students’ performance assessment and educational outcomes.
Ensure reliability by tracking application health, performance, and security-related events to enable quick issue identification and resolution. Last but not least, we can implement CI/CD pipelines with automated testing to secure the reliability of deployments and changes.
Security
Maintaining the security of our system is essential to protecting sensitive student data and ensuring the accuracy of test results. Preventing unauthorized access, data breaches, and cheating during test administration and grading is also essential to upholding the system’s credibility.
- OAuth 2.0 and Azure AD: Secure API access with OAuth 2.0, utilizing Azure AD for robust identity and access management.
- Access Control: Implement role-based access control (RBAC) to ensure users can only access and perform actions appropriate to their role.
- Secure Coding Practices: Follow secure coding practices to protect against common vulnerabilities.
- Compliance and Auditing: Ensure the system meets relevant compliance standards and implement auditing mechanisms to track access and changes, facilitating the change approval process.
Scalability
Maintaining the security of the statewide standardized testing system is essential to protecting sensitive student data and ensuring the accuracy of test results. Preventing unauthorized access, data breaches, and cheating during test administration and grading is also essential to upholding the system’s credibility and trustworthiness.
It is essential to design for scalability and take advantage of Azure’s global infrastructure and services, such as VMSS, for dynamic scaling. Auto-scaling is another helpful feature that automatically scales application services and databases based on usage, ensuring the system remains responsive during peak periods. By auto-scaling for application and database services, we can adjust resources found on demand without manual intervention, ensuring that the system can handle peak times during testing periods.
API Design and Patterns
RESTful APIs are the ideal choice for our standardized testing system for the following reasons:
- Scaling and resource management make it perfect for supporting over 40,000 students and 2,000 graders during peak testing times.
- REST’s use of standard HTTP methods aligns with the straightforward interactions required for submitting tests and retrieving questions. This simplifies development and integration across the varied user base.
- Support for HTTP caching, the server can efficiently serve frequently accessed data, such as test content. This improves responsiveness and reduces server load.
- Implements standard web security protocols, ensuring the protection of sensitive student and test data.
With these qualities, RESTful APIs provide an efficient, user-friendly, and secure solution for our testing system’s needs.
Cloud-Based Infrastructure
Leveraging a cloud provider to host the application allows scalability, reliability, and security. Given that the state outsources its hosting center, a cloud platform can provide the necessary infrastructure to support the varying load of 40,000+ students and other users.
To build an effective system, it is recommended to use cloud services such as compute instances for the application servers, managed databases to store test scores and user data, and storage services for backups and logs.
Additional context consideration
Establishing a transparent change management and deployment process that includes testing and review stages is vital to meet the requirement for a change approval process involving three government agencies. We should develop a clear and straightforward method for managing updates that provides for testing, review, and approval stages. This is especially important given the multi-agency change approval requirement.
Since we need to defent our budget each fiscal year we need to ensure that we are using resources efficiently. In order to regularly review and optimize resource we can use for example Azure Cost Management tools that can help with this. Using Azure Cost Management we can periodically review cloud resource usage and costs to ensure we are minimizing spending. Where possible, we can take advantage of reserved instances or sustained use discounts. Additionally, we should prepare detailed reports and justifications for budget reviews, highlighting the system’s efficiency and effectiveness.
Wrapping up our analysis on setting up a statewide standardized testing system, it’s been a solid run-through on what to think about when building something from small to complex. We dived into how breaking things down into microservices can help manage different tasks like test taking, grading, and user management, and why ensuring the system can handle the load, stays up when needed, responds quickly, and maintains data safe is super important.
But let’s be clear: what we’ve sketched out here is more like brainstorming or a mock-up than a final plan. Building the actual architecture for a system like this requires much more digging and tweaking. It’s like laying down the first draft in a series of revisions. There is always room to evolve and clean the approach as we get deeper into the work.