mcq-test-results-js
I had originally thought to write this service using Rust and Postgres as the data store,
but after some consideration I decided to use JavaScript (not TypeScript) to iterate quickly,
spend less time fighting with the borrow checker or tweaking moduleResolution in a tsconfig.json
and focus on aspects I considered to be important:
- clean modular code
- dependency injection
- easily extensible integration tests
- See
src/api.test.js
- See
Plus, it's just a prototype right? :P
I chose SQLite to simplify the deployment and running of the service, as it can be tricky ensuring that a separate DB service is migrated and running before the service starts trying to connect. Additionally it allows the integration tests to use the database layer without having to run multiple services inside a compose network. Finally I wanted to use SQL features like transactions and check constraints to meet requirements of atomicity due to unpaid AWS bills.
Regarding the XML parsing, I chose to use a library with a simple API and be quite generous in what I accepted in requests instead of using a schema and instead let the application and database layers enforce missing or invalid fields.
Using the Service
Starting the Service
docker compose up
localhost:4567 is forwarded to the listening service inside docker.
Tests
Running tests requires NPM to be installed, if you have it you can simply run
npm i
npm t
This will install the dependencies and run the tests.
Note that the database on your host machine will not be shared with the instance running inside docker.
Deployment
You can find the built service image with
docker images | grep mcq-test-results
This image can then be tagged and pushed to the appropriate container registry to be run in ECS, or EKS, or whatever container service it is we use here at Markr...
IMPORTANT
In order for the service's data to be persisted the directory /opt/mcq-test-results/db must be mounted as a high write speed persistent block store.
Next Steps
Migrate to PostgreSQL
Postgres has excellent built in aggregate functions such as percentile_cont that will likely outperform the application level calculations being done by the simple-statistics library used here.
Logging
The application has very little in the way of logging. Suggest a JSON logging library such as Bunyan to improve debugging and traceability of the application.
Assumptions
Student Uniqueness
The sample data didn't seem to make a great deal of sense; perhaps our friend at the school board butchered it redacting student PII.
It contained entries where for example:
- the same
student-numberwas supplied by students with different names- John John & Jean Stephanie both supplied 2398
- students with the same name supplied different
student-numbers- there are 3 Penelope Graces (!) all supplying different student numbers
Here I assumed that the students and teacher are smart enough to know their names and student numbers and consider them to be unique individuals based on the combination of those attributes. ...then again maybe they're just messing with the teacher...
On Selecting the highest score
When inserting entries into the database, a row is only inserted or updated if the marksObtained are greater than the value
of an existing row.
I had originally thought to standardise the marksAvailable based on the highest value seen in any entry for a given testId
but I didn't know definitively that a test should all have the same marksAvailable. The test data didn't seem to indicate that the machines could submit any entries to the contrary either.
Size Limits
20MB is assumed to be the maximum test submission size