This document has been created to showcase my UX research and analytics abilities. The contents of this document are based on an actual project, but all identifying information has been removed. Although the numerical data is fictitious, it accurately reflects real patterns found in the data. This document serves as a semi-formal report intended for a non-technical internal audience.
I was tasked with end-to-end execution of project Z during 2023 - 2024. The project involved building a reporting system that will allow stakeholders in the company to retrieve clients' input on different products without manually obtaining detailed report from the research team.
Skills: R, Python, RShiny, CSS, HTML, SQL, API, Analytics, Visualization, UX
Departments Involved: Research (my department), UX, Software Engineering, IT, Product
With a lean budget, the technical requirement for the system are:
Must be secured with a log-in requirement for all intended users.
Must be able to produce reports that are 100% customizable in the back-end
Must be able to output a downloadable version of the report that is 100% branded according to the company aesthetic.
Must be improved continuously based on stakeholders feedback.
With all these requirements and budget constraints, I decided to build an RShiny web app, hosted on an internal server:
IT can maintain the server that provides a secure log-in system.
Shiny web apps can output any type of R or Python files, allowing for reporting outputs such as Markdown in both HTML and Word/PDF versions. These files contain manual data pulling, cleaning, and visualization codes that can be customizable, different from drag and drop platforms maintained by a 3rd party vendor.
Markdown documents supports template referencing with familiar file type such as Word Template, PowerPoint Template, and CSS, allowing myself to work freely with our UI designer for report optimization.
Publishing an app file can be done quickly after QA, making it easy to implement changes safely.
Below is the altered version of the end-product after rounds of iterations. The real end-product cannot be shown outside of the company. Because I am not able to show the actual name of the system, I will call it “Product Input Database” in this portfolio.
Image rendered through Figma.
I performed around 2 main optimizations per month, although all optimization plans cannot be detailed in this document, below are important ones that were executed successfully, leading to increased efficiency, download, and adoption rates.
The bar chart below illustrates the average number of times users edit each input field before finalizing their input and retrieving a report in an RShiny web application. This metric provides insight into user interaction patterns and potential usability issues within the form.
Prior to the final rendition of the web application, there were two fields for client’s information: Client ID and Client Name.
Client ID was edited the most (3.6 times on average), suggesting potential difficulties in inputting or recalling the correct information.
Client Name followed closely with 3.2 edits, indicating users may be uncertain about formatting or entry requirements.
Besides obtaining these descriptive statistics, we (the research team) ran a usability testing and distributed survey across our product, customer success, sales, and marketing department, retrieving a confirmation that these two fields need to change.
I implemented a technical solution by consolidating the fields and programmed an automated client account detection in the back-end. By entering the client ID, the field becomes populated with both the found ID and client name, so that the user can immediately see if they are entering the intended account information.
In the back-end, I pull both the input dataset and join it with a large dataset from our CRM, allowing for the field to be autopopulated in real-time.
Besides consolidating the field, we also noticed that:
I realized that the names of each input report may be confusing, so I worked with product to re-name our reports and upload a report FAQ document that is linked at the top of the web application.
This is the result after 4 weeks of optimization:
No changes were made to the remaining two fields that were structured well.
I recorded the run time for generating each report type, as the report was generated in real-time, pulling from a large dataset with heavy reporting and visualization code, the wait time could deter users from generating reports effectively.
As we can see, report type 1 through 4 have retrieval run time over 7.5 seconds, which is longer than our standard.
The retrieval run time became an important issue to tackle, as we realize that the importance reports had run time higher than standard. Users need to obtain these reports for important optimization processes, so having a quicker run time was incredibly important.
I realized that the original code were written with redundancy and the data gathering system lacked simplification. These were a few things I did to optimize retrieval run time.
1. Efficient Data Handling
Passing Numeric Parameters Instead of Strings: I worked with the engineer team to modify data queries (during gathering from product front-end) by passing numeric IDs rather than string values to the datasource. This significantly reduced query processing time, as numeric indexing is far more efficient than string-based lookups.
Using Custom Parameter Indexing: Instead of
relying on raw survey responses (which are often free-text and difficult
to parse immediately), I structured API requests to utilize a custom
parameter index. This allowed for faster retrieval of data when using
httr::GET(), as indexed queries return results more
efficiently.
2. R Code Optimization
Vectorization Over Loops: Replacing slow
for loops with apply(), lapply(),
or dplyr operations (e.g., mutate() instead of
row-wise processing) speeds up computations.
Preloading and Caching Data: For reports
frequently requested, I implemented caching mechanisms using
memoise::memoise() to store previously retrieved results,
reducing redundant API calls.
Using Data.table for Large Data: Switching from
data.frame to data.table significantly boosted
performance, especially for filtering and aggregations.
3. Visualization Performance Enhancements
Avoiding Over-Plotting: For large datasets, I
used ggplot2::geom_hex() or
ggplot2::geom_density2d() instead of plotting every
individual point, making visualizations clearer and rendering
faster.
Lazy Loading and Sampling: When working with
large datasets, I used dplyr::sample_n() or
slice_sample() to display a subset of data interactively
before generating the final full report.
4. API and Data Query Performance
Minimizing API Calls: I structured queries to request only essential fields rather than entire datasets. By limiting API payloads, I reduced response time significantly.
Batch Processing: When multiple reports needed
to be generated, I batched API calls together using
purrr::map() rather than sending sequential
requests.
Following 4 weeks of optimization, these were the retrieval run time:
A good tool is one that people can actually use. It doesn't matter how advanced or sophisticated it is if the intended users don't know how to use it. This is where I had to step in as a strategist and a human, understanding their needs, guiding them, and ensuring the tool became truly valuable across teams.
Our adoption rate company-wide (for intended users) was 49%
We gathered data on the tool adoption to improve our communication process.
Although the product team is the main user of our tool, we designed the tool to export client-facing reports so that they can see their own employee’s feedback for our products as well. With an overwhelming of positive verbal feedback in the past, the company utilized the data for growth and revenue security. So, this database was put in place to also distribute this data systematically to clients by our CSMs (Client Success Managers) and AEs (Account Executives). At the same time, marketing could use valuable positive feedback to optimize their marketing campaigns.
With this in mind, I had to come up with a plan to lead communication and education for all departments, not just product. These are what I did:
Tailored Training for Each Department - I worked with learning managers and sales enablement to create training modules of the system. Detailing the importance of each report, why we needed them, and how to retrieve them successfully. We put out monthly announcement for optimization updates and engage them by inviting them to provide feedback freely at anytime.
Built Automated Workflows - I worked with the Sales analytics team to co-create a notification system that will allow all stakeholders to be notified when a report is ready to be retrieved from the database. This involved integrating multiple platforms via API tools.
Create a Centralized Knowledge Hub - At the top of the database, I created a comprehensive knowledge hub about the reports and how to retrieve them. This knowledge hub can be shared and access from outside the database interface as well.
Offer Drop-In Sessions for 8 weeks - I made it clear that I truly appreciated anyone who asked questions and wanting to learn and utilize the database. Many people were not comfortable with this technology, yet they still reached out and demonstrated readiness to learn. I encouraged everyone to reach out with any questions– and no question is too “simple” or “stupid”. I also offered drop-in sessions for stakeholders to come join me to learn more about the tool.
After 4.5 months of re-structuring communication plans our adoption rate increased to 88% for company-wide intended users. Below is the breakdown data:
Thank for you reviewing my portfolio.
If you are interested in learning more or would like to connect, please feel free to contact me at my email shown on silarat.crd.co.