IS480 Team wiki: 2016T1 IPMAN Midterm Wiki
- 1 Project Progress Summary
- 2 Project Management
- 3 Quality of Product
- 4 Reflection
Project Progress Summary
Project Highlights [in chronological order]
- Implementation of Facebook Login, due to unfamiliarity, we took 2 weeks to learn and implement this function in Sprint 3
- Integration with QR code implemented by sponsors so that labels can be pre-populated once code is scanned in Sprint 5
- Conducted our first UAT with our sponsors and packers in Sprint 6 to test our process order and customer management module and worked on Performance and Design Improvements in Sprint 6
- Decision made in Sprint 7 to shift several tasks for subsequent sprints due to greater focus on smart marketing and dashboard graph modules as requested by sponsor. Dropped Facebook bot and recommendation engine (planned for Sprint 12) so that we could spend more time on these two modules.
- Conducted our second UAT with our sponsors and their business development in-charge in Sprint 9 to provide feedback mainly on our smart marketing module
- Integration of Intercom together with our system in Sprint 10
Access the detailed progress of functionalities here: IPMAN Functionalities Progress List
Project Schedule (Plan vs. Actual)
Several changes were made to the project schedule due to greater emphasis on Smart Marketing module and Dashboard Graph module as requested by sponsors. Hence, IPMAN has dropped several tasks that were scheduled in subsequent sprints to focus on these changes (as reflected in the actual schedule). Progress of the team is well-paced and optimistic.
Planned Project Schedule
Actual Project Schedule
From the period of Acceptance till Mid-Terms, we will like to highlight that our concerns were 1) Technical Risk and 2) Stakeholder Management Risk as described below:
|S/N||Risk Type||Risk Event||Likelihood||Impact Level||Category||Strategy Adopted||Actions|
|9||Technical Risk||Team IPMAN was unable to deploy as soon as all the bugs were resolved. Whenever sponsors report for bug issues, team immediately resolves the bugs. However, team IPMAN was unable to deploy the application with the fixed bugs as team was still building on the features in the current sprint and would only deploy the application at the end of the sprint when all features were completed.||High||High||A||Mitigate||Team IPMAN came out with another branch for deployment which means there are now 2 branches, one of it is the deployment branch and another branch is to work on the existing features. Therefore, whenever sponsor raises any bug, team IPMAN would be able to resolve the bugs and deploy immediately without waiting for the features to be completed at the end of the sprint.|
|10||Stakeholder Management Risk||Team IPMAN had to manage not only sponsors but also the developer team that the sponsors engaged. For instance, the freelancer developers have utilized Intercom to track the customers’ interaction on the application. This feature implemented affected the Smart Marketing features that we built.||High||High||A||Mitigate||Team IPMAN communicated with sponsors early and found out more the implementation of Intercom. Team IPMAN also constantly met up with sponsor and checked with him about the progress of Intercom. Team IPMAN followed communication protocol between the sponsors, developer team and team IPMAN. Team IPMAN is using Trello and Telegram for communications and updates.|
Use of Adapter Pattern
In order to communicate with Mailchimp services from our web application, we have to make calls to Mailchimp’s RESTful API services. However, we do not want to call these APIs directly from our controller, as it would mean that API calls to fetch similar data would be repeated.
How do we ensure that our main application can reuse the code that calls these RESTful services, as well as protect our main application from changes to Mailchimp’s API?
We solve this by using the Adapter Pattern. The high-level overview is shown below:
Using the above as an example, we delegate the responsibility of calling MailChimp’s RESTful API to the module mailchimp_api.py. In doing so, we can centralize all of the Mailchimp API related code. If Mailchimp decides to change their API interface (e.g. add a new field), only one module will be affected (Adapter – mailchimp_api.py), and we would only have to make changes there. Below is an example of the code from mailchimp_api.py module.
When the actual call is made from the browser to our application, the resulting call graph is as below. As you can see, because all the methods in our app call Mailchimp’s RESTful services through the mailchimp_api.py module, we are able reduce change effort by reducing coupling, and the impacted modules from a change in Mailchimp’s API would only be at mailchimp_api.py. This can be seen from a modified call-graph generated using pycallgraph, as below:
Capturing MailChimp Statistics
Hookcoffee extensively uses email marketing to push out their products. However, while Mailchimp provides the capability to keep track of who has opened the email and who has clicked through, for any given campaign, the activities that the prospective customer has on the website is invisible to the owners.
Mailchimp provides an eCommerce tracking option which enables web developers to record revenue generated from their campaigns, but fail to provide granularity in the sales funnel. For instance, did the customer register their interest on the site? Or did they make a purchase or was engaged in the campaign in a positive way (switching to a different type of coffee).
Previously, it was invisible to HookCoffee what happens at that level. However, by building on top of the eCommerce function, we are able to fetch who the user is and from which campaign he was from by interacting with Mailchimp’s RESTful APIs. We also recorded what the user did AFTER they clicked through the email campaign on the local database.
However, the issue came when we found out that Mailchimp actually stores critical details after the clickthrough on the request itself as parameters on the request, as shown below.
This meant that for every end point, we have to capture these parameters and store them in session, as shown below.
The naïve method is to go into every single url view endpoint and add a method to capture such data, but this proved to be impossible, due to the large number of possible endpoints. Furthermore, as the project went on, we cannot guarantee that all these endpoints will capture the data as other freelancers are also working on the same website.
We used the Decorator pattern to handle this. The decorator is an additional functionality we can add without affecting current implementations. Think of it as a plugin for a web browser.
There exists a plugin to bind decorators to a url.py file, however, there was no indication of how we would do it on the same file. We dig deeper and realize the urls.py is automatically exported as a list in Django. Now, we store all URL patterns as a list of unwrapped (or undecorated) URL patterns. We then hook our own decorator (processMailchimpParams, which takes a request and stores the mailchimp campaign id and resolve the email address if it exists) to the list of unwrapped URL patterns, thereby causing it to execute for every endpoint (with the exception of static pages, e.g. images). This enables an easy to use solution that is easily extensible by other developers on the team, as modifications are made on the same file.
Comparison Using Hashes
HookCoffee is a subscription service that ships out coffee to its users, hence they have to print addresses and labels for each order. However, the generation for these labels/addresses tend to be slow, in the order of minutes (and increases even more as the number of labels grow large). As you can see, the previous system wasn’t designed to handle large number of orders (having multiple print label buttons). So, how do we make it fast?
We experimented with different libraries and found out that the problem was inherent within the pdf generation itself, so we traded space for time, i.e. we chose to generate the labels as soon as they are created, way before the time when the order is process.
For this, we implemented a task scheduler, celery, to create tasks to pregenerate the labels and we deployed the task scheduler on their live server. However, there came another issue: orders can change all the time and there are many different ways that it can change. There are too many endpoints to which the order can be changed (e.g. customer’s name, customer’s address, order details, directly through the database, the Django Admin, etc.). The problem is further exacerbated by foreign key dependencies, so any changes in these tables would have to be reflected in the pregenerated labels. The order table is shown below:
In such a complex situation, how do we ensure the pre-generated labels are up to date?
The solution: Hashing
We convert each order to a String. This string is passed to a hash function, SHA-256, which generates a fixed-length digest which is unique to each order (which is tied to every detail in the order). We are also able to attach relevant metadata as well.
For example, if a customer ordered Guji Liya today, it would produce an order label that is of the file name
Let’s assume Guji Liya is no longer in stock and the packers at HookCoffee hence changed it to NeverEverLand.
The system hashes the order (which is now f7e3f23927d8e2921e52aefce5dbf544) and finds that there is a mismatch in hashes, hence the system will generate a new label for the order.
Quality of Product
|Topic of Interest||Link|
|Project Management||Project Schedule|
|Project Overview||Project Overview|
|Project Documentation||Personas & Scenarios|
|Low & Mid Fidelity Prototypes|
For easier reference on testing done on our system, the team has came up with this step-by-step process as seen below:
For a more detailed explanation on Team IPMAN's internal testing methodology, view our testing page as linked in the Intermediate Deliverables component.
User Acceptance Test 1 & 2
Team IPMAN has conducted 2 user tests which allowed us to better manage sponsor expectations as well as improve on usability of our application interface.
For more detailed version of Team IPMAN's user acceptance test results, assess here:
This journey has proven to be an enriching learning process for Team IPMAN. We have learnt immensely from one another's strengths and weaknesses and were able to proficiently complement our different working styles.
We have also learnt that communication, compromise and active participation is key to ensure a collaborative learning environment. In addition, together with our generous sponsors who have provided the flexibility and autonomy to work with real data, we have enjoyed working on this project.