Building NgResume
Behind-the-Scenes
about the project_
NgResume was the child of the frustration of having to meddle with Microsoft Word whenever I needed to edit my resume. Realizing that the data structure of a resume is relatively constant, I decided to try coding the template I have been using into an auto-generation tool. When the thought of edit support and usability came into place, I asked Gwen if she would like to join in the fun, and when she agreed, the two-people Scrum Team was born.
Year 2021
Status Ongoing
Stack Angular, Typescript
Repository GitHub
CI Travis CI
CD/Hosting Netlify
Scrum Board Trello
Code Editor VSCode
Design Tool Figma
Product Owner & UI Designer Gwendolin Tan
Scrum Master & Front-end Developer Stevanus Satria
Back-end Developer Zeyao Liu
sprint 1_
The aim of this Sprint was to get the most valuable piece of code out: the PDF generation logic. At work, my colleague had used jsPDF to support exporting of our application’s data into a PDF format, and I decided to use the same open-source library for this project.
I had taken some time prior to this week to outline the JSON structure of the resume. Hence, the bulk of the coding session revolved around understanding the library and coming up with a logic for the PDF generation.
I spent the next hour tinkering with the library to understand the available APIs. I came to understand that the library utilizes coordinates and alignment properties to correctly render the texts and lines on the page. This was crucial as any mistakes in the coordinates provided will cause the rendered items to overlap one another. I also came to understand that the dimension and orientation of the page were declared during the instantiation of a new jsPDF instance.
Given the nature of the library, I decided that a incremental cursor-based approach to generating the PDF. The cursor will by default start at (0, 0). I would then code a logic to move the cursor to the position I wanted the text/line to be at, and render the text/line. Afterwards, I will move the cursor to the next position and repeat the rendering step. This approach helped not only in my visualization as I coded the logic, but also in making testing and margin checks easier.
One challenge that took me some time to figure out was loading custom fonts, as I was not familiar with reading and converting the .ttf file into the required format. After tinkering for a while, I was relieved to find that jsPDF provided the conversion tool needed. Within the next few minutes, the challenge was overcome.
The entire PDF generation logic was completed in half a day’s worth of coding. However, the code was not very maintainable nor was it very testable. Nonetheless, testing with my current resume data showed that the logic worked as designed. As jsPDF also supported opening the generated PDF in a new tab, I managed to mark both the “Generate Resume from JSON” and “View Generated PDF before Download” tickets as done. I had not written a single automated unit test yet, but I figured that given the CI/CD pipeline was not established yet, it would be more valuable to deliver the automated unit tests as part of the CI/CD pipeline User Story.
sprint 2_
The aim of this Sprint was to establish a CI/CD pipeline for this project and achieve more than 90% code coverage.
By the end of Sprint 1, I had actually set up a CD pipeline for the project, as any changes made to the code will be automatically built on Netlify. However, I was unable to get the coverage data out of Netlify without reading through the build logs. I went on to read about establishing CI/CD pipeline for an Angular project deployed on Netlify, and found that it’s possible to route the build process through Travis CI. This way, upon successful build, I could ask Travis CI to send the coverage report to another tool before deploying the production build on Netlify, thus achieving the goal of the Sprint!
As I have worked with Travis CI before, it didn’t take me long to set it up for this project. The challenges, however, were on integrating Codecov, getting the credentials and correct command to send the build to Netlify, and removing the automatic publication of changes from GitHub on Netlify. Somehow the last point took the longest to resolve, but I finally found the answer on the Netlify Support Page.
With that, what was left was improving the coverage level of the project. I had to first refactor the PDF generation code into smaller chunks per section. Once that was completed, I began covering the most critical aspect of the code: the wrapper functions for jsPDF library. Finally, I went on to cover each section’s logic, before ensuring that the core logic calls cascaded down into the jsPDF API level.
It took a few sessions of coding after work in order to set every up and get to a coverage level of 94.4%. With that, I managed to mark “Setup CI/CD Pipeline and Write Unit Tests” as done!
sprint 3_
I had initially hoped we can get to the meat of the development work in Sprint 3, but circumstances and changes to the project meant both Sprint 3’s scope and the Product Backlog had to be adjusted.
Before I get to what we delivered this Sprint, let me highlight the positive change to our project: we got ourselves a Back-end Developer in Zeyao Liu! We had all worked for the same company before, and are excited for what he might bring to the table! Account creation, data storage, resume versioning are all possibilities now, just to name a few.
So, what did I deliver this Sprint? Well, commemorating the addition to our small Scrum Team, I thought what better way to do so than to complete the write-up on the About page. While doing so, I took some time to polish the UI up a little bit, and provided support for drag-and-drop file upload. With this, users no longer need to navigate through the file hierarchy when trying to upload the JSON file, which can be tedious for some. Instead, they can rely on the search functionality provided in most modern desktop OS, and upon finding the correct JSON file, drag it into the “drop zone” on the app’s UI. I also improved the error handling and feedback to the user, hopefully making the app more usable in general.
I ensured that all the additional logic blocks coded were covered, and I am proud to announce that we now reached 96% coverage. Onward to Sprint 4!
sprint 4_
It was not a great Sprint at all for the Team 🙁 Although we had a fantastic kick-off meeting on Monday, we made little progress this Sprint due to extra personal and professional commitment. I have an upcoming Certified Usability Analyst (CUA) examination to study for, so most of the post-work and weekend free time slots were used for revision. Zeyao was moving house whereas Gwen was busy handling requirements at work.
Hence, we did not deliver any user stories this Sprint, although I spent some time to design the form structure and reading up on nested + dynamic forms on Angular. Hopefully, I pass the CUA examination in one sitting, and can focus my attention back to NgResume from Wednesday onwards.
Deepest apologies from all of us, and we will do better next Sprint!
sprint 5_
Finally, after an unproductive Sprint 4, we are back on track for Sprint 5!
On the back-end side of things, Zeyao has done a draft design of the database and entities, as well as starting exploration to containerize the App. On my side, I managed to get the dynamic form done! While thinking about how to achieve this, I deliberated on whether to convert the current PDF generation file into an injectable service and convert the JSON model into a Reactive Form model. However, I remembered that we wanted users to be able to save the modifications he/she made into a file, and having a JSON structure stringified is the best and simplest way to do so. This also allowed me to leave the current implementation largely untouched. Hence, I decided to keep the JSON model, and instead allow data to be updated between the JSON model and the Reactive Form model.
Unfortunately, it’s still lacking the beautifying aspect from CSS as well as the ability to add or remove some of the form entries. Unit tests addition is also due. However, we now have a working prototype where users can create/upload, see the data displayed, edit, before generating the PDF!
Onto Sprint 6~
sprint 6_
For front-end, Sprint 6 was all about beautification, Dynamic Form, and unit tests.
Firstly, beautification. True to my comfort in using Bootstrap, the layout was almost entirely based on Bootstrap’s Grid System. The only exception was the “Remove” button for the Dynamic Form, which we will get to in a bit. As for the design aesthetics, I tried to imitate modern form designs, where only the bottom borders were visible for the input HTML elements. However, this was definitely not the final design, as the overall design guideline was yet to be completed by our UI designer.
Next up is the Dynamic Form, which is probably the most important delivery of the Sprint. As mentioned previously, whereas Sprint 5’s delivery allowed for edits to be made to the uploaded data, it did not allow dynamic addition/removal of entries such as work experience, its descriptions, education, and awards or certifications. This severely limited the usability of NgResume. By implementing this ability following Angular’s best practices, the Minimum Viable Product (MVP) for NgResume was finally completed!
To top it off, I added unit tests to cover the entire Sprint 5 and 6 deliveries, and as the icing on the cake, I also implemented the ability to save the edited resume data into a new file! 🙂
Sprint 7, here we go!
sprint 7_
Bug-busting Sprint!
There were a couple of UI and functional bugs squashed during this Sprint. They included wrong alignment in mobile view, as well as improper validation where optional fields were marked as mandatory. They were both simple CSS and logic fixes on front-end side. I also added some unit tests to safeguard the changes.
The other major task was to add validation look-and-feel to the UI. I decided to also add indicators on which fields are mandatory. Whereas the latter was simple, the former proved tricky for the dynamic input fields. I struggled to access the HTML tag programmatically, and didn’t manage to add the validation on the micro-level. In the interest of delivering value, negotiated with the Product Owner to have those added as part of a separate ticket. Will continue to explore how to do so in the coming weeks!
As for back-end, seems like Zeyao has completed the basic setup. He decided to create a separate repo for the back-end implementation. A little bit more fine-tuning, and we’re ready to start working on the account creation and management features!
Until then, onto Sprint 8~
sprint 8_
On the UI, Sprint 8 was about completing what was incomplete on Sprint 7, which was to validate the inner form groups as well. We’ve finally got that down! I also added a code to add meta tags to our HTML 🙂
Other than that, we continued evaluating which platform to host our back-end on. Currently, Heroku seemed to be leading, but we still consider AWS and others as well.
Onward to Sprint 9!
sprint 9_
Sprint 9 was a back-end focused sprint. Zeyao did a lot of tinkering and began setting up the database for user account creation, whereas I continued researching on where to deploy the app. I think we will try with Heroku for starters 🙂
And on the UI, I fixed a small bug that caused a lost of punctuations on the company name.
I know that our progress has been slowing down since the MVP was released, but we hope to get everything ramped up again once the back-end setup is completed!
With that said, onward to Sprint 10!
sprint 10_
Sprint 10 was predominantly all about exploring back-end deployment, and we hit a stumbling block as the deployment of the DB to Heroku is failing. Nonetheless, Zeyao continued to work on the establishment of a user account creation and save capabilities for NgResume.
And we now have a flow wireframe for NgResume! Gwen has completed her first draft, and will continue to work on the detailed mock-up for me to update the UI with 🙂
With that said, we’d like to take the time to welcome our newest member, Risa, and onward to Sprint 11!
sprint 11_
Sprint 11 was my chance to get back to my front-end development roots and enhance the functionality of the UI. It’s not at its ideal UX yet as we are still waiting for the final UI mock-up, but I added the missing dynamic forms into NgResume! Now users are able to add multi-line for more items in his/her resume~
We also make good progress on the back-end development, with Risa helping out with our APIs.
Onward to Sprint 12!
sprint 12 & 13_
Sprint 12 and 13 are mainly technical and back-end related sprints. Zeyao and Risa continue to work on the back-end. I tried to read more into the deployment problems as well, but work has been taking a lot of time so it’s been causing delays on this front.
Onward to Sprint 14!
sprint 14_
Back-end API is completed in Sprint 14! Zeyao has been working really hard on this, and I am stoked to try out the integration in the upcoming Sprint.
With that said, onward to Sprint 15!
sprint 15_
I finally updated the JSON format used by the front-end in Sprint 15. With this, the UI is finally read for integration with the back-end. We are still facing issues with deployment, however, but we’ll figure it out as we begin the full-stack integration for NgResume 🙂
Sprint 16, here we go!