I finished up last week with finalizing the underlying logic that powers the bulk registration module. This was only roughly half the work that was needed to complete this card – the last half consisted mostly of updating the controller and the bulk registration page to use the new code I had written.
Parsing The Information for Bulk Registration
I needed a way to see how the data was going to be passed from the front end to the back end, so I built out the barebones form (that would later be expanded upon when needed) that I could use to test passing data to the server. I parsed the date and group information from the request and created an instance of that details object I had created last week. I then spent some time going down a couple avenues to do the Excel file parsing, but ultimately ended up asking my boss for help and was pointed at some code from another project we had that did exactly what I was looking for. I created a new model to parse the necessary data into despite only currently needing data from one of the several available Excel columns. I figured if we ever needed more of that data, it would be pretty easy to just add a new field to the model, so I might as well spend the minimal extra effort to save some time in the future. After some refactoring of the parsing code, I got to work on the logic behind collecting all the people who needed to be registered.
Building the List of People to Register
I did not write tests to build up this functionality against, so I effectively failed my goal for this module to be completely test driven, but I did end up having to write tests to verify everything was working in the end. The process for determining who could and could not be registered was fairly simple, though it did take about two days to complete, and then another day to write tests and refactor.
From the Excel spreadsheet I was able to get a list of student IDs that needed to be registered – the big caveat here is that some of the IDs were for people who already existed in our database, some were for people who existed in the university’s student database but not ours, and some of them did not exist anywhere (though this case seems mostly to occur with typos by whoever entered the offending ID into the spreadsheet).
With all this in mind I mulled over a solution and landed on the following. I would use the list of IDs parsed from the spreadsheet and query our database for anyone we know about. I would then get a list of IDs from those known people, and then get the difference between the spreadsheet ID list and the known person ID list. This new list would give me everyone who I was given in the spreadsheet that our database does not know about. From here I could check each unknown ID against the university’s service – if it existed I would create a new person in our database using the university’s information, if not I would add the ID to a list of invalid IDs (that would then be later displayed on the page after all people were done being processed). By concatenating the list of known people with the list of all newly created people, I would have the complete list of all people who needed to be registered. I implemented this solution with a few snags over the course of about a little less than a day.
One problem I ran into while to working through this was how to effectively return both a list of people to be registered and a list of all invalid student IDs. Initially I was passing a list from the controller down to my helper classes, but this implementation felt cluttered – I would rather be returning a value than passing in a parameter and crossing my fingers that it gets updated correctly. I ended up doing some refactoring to include a new class that would encapsulate both of these lists. With this new class my code became noticeably more readable and concise, which is basically all I could ever hope for when I’m programming.
Bringing It All Together
I had all the pieces of the puzzle now – I had the parsed group and arrival information, I had all the invalid student IDs, and I had all the people to be registered. The next step was to process registrations for all of these people using the work I had finished last week. This was all fine and dandy until I realized that there might be a point of potential confusion in this process. One of the rules of the registration helper I had built essentially forced a person to be skipped if they met a very specific criteria. And while this case should be pretty uncommon in practice, I decided that it would be worth it to display not only the student IDs that were invalid, but also those that were skipped during the bulk registration process. This led to some additions and subsequent refactoring that put my tests to good use as some of the logic that once lived in that helper I built got moved up a level of abstraction. Without those tests I would have been very anxious that this change would break everything, but because I had the tests to verify no behavior was changed with this alteration, I was able to proceed with the utmost confidence.
The final step was updating how that form I had been abusing for the last couple of days. I needed to populate it with a list of group information for the users to select from, but I also needed to later display the invalid and skipped student IDs, so I opted to create a view model to hold this data. I verified that everything was working as intended with the new list of correct groups and then moved on to making the page actually look nice. I paired with one of the designers in the office for about an hour or so and got the page into a much more usable state with nice spacing, fonts, etc. I can use CSS pretty well, but I am certainly no artist with it.
Now that I was displaying the list of student IDs on the page after the Excel spreadsheet had been processed, I realized that while there were two “kinds” of IDs being shown, there was exactly zero distinction between them. I updated the code where I added these IDs to also have a short message lending the necessary context to why there were added to the list.
At this point it was starting to get close to the end of the day on Friday and I wanted to have something deployed to QA before I left for the weekend. I had a few small additions that we needed to really call this module 100% complete, but my boss agreed that we could just do a pull request and worry about the other small changes next week – this would allow for the stuff I had just finished to be QA’d while I worked on the additions.
I submitted said pull request to merge into the dev branch and did code review with my boss for the better part of an hour. The main addition that came out of this review was a slight rewrite in how those student ID error messages were being generated. We decided that it would make stylistic sense to have the IDs contrasted from the rest of the error message, but there was no easy way to do that given how they were currently built (really just a list of strings that were displayed in the view). We ended up building a new error message model that had a field for the student ID and the actually error message itself – this way we could render the ID in a span that could be styled separately from the rest of the error message. Inevitably some things were refactored, but for the most part they were relatively minor fixes that helped to centralize the context for these error messages to the location in the application where they were being generated.
I was really satisfied with how I left my project when I left for the weekend. In the past two weeks I rewrote a huge part of the application and was able to deliver a new version of the bulk register module that we have a much higher level of confidence in. You don’t even have to take my word for it because there is a suite of tests around all the new code that verifies that it is in proper working order. I look forward to getting to practice more TDD in the future – hopefully once I finish the small additional features for bulk register next week I can try and apply these same strategies to whatever card I pick up after.