top of page

Tulip Co-op

Software Developer

Summer 2018

ABOUT TULIP

Tulip is a Canadian tech company based out of Toronto and Kitchener. Founded in 2013, the company develops mobile applications for Apple's iOS platform focused on empowering store associates. Tulip's mobile app typically contains features such as a Product Catalog (where an associate can browse for items that a customer in the store might like), Clienteling (a technique used by retail associates to establish relationships with key customers based on data about their preferences, behaviours and purchases), and Checkout.

​

                                                 include Michael Kors, Saks Fifth Avenue, Kate Spade, and Indigo.

fulfillment-workflow-2.png

© Tulip

runner-requests1.png

© Tulip

About Tulip
About The Job

ABOUT THE JOB

This was my third work-term at Tulip. For my previous two terms I worked as an iOS Developer creating a mobile-point-of-sale app for Indigo. (You can read about my experience working in that position job        . Be sure to check out the "2018 Update" section!)

​

This Summer I worked as a Software Developer on the Platform team. Within this team I was part of the Authentication sub-team. The Platform team is responsible for all of the backend features that support the core framework in the iOS apps (for clients) as well as several online tools that help clients configure the app to their needs. The Authentication team is responsible for...authentication. More specifically, Tulip uses OAuth2 and SAML to handle user login/logout and API access tokens. The code base consists mainly of PHP and Go. Prior to starting this job I had no experience working with any of these languages in a workplace environment.

​

Throughout the four months, I worked on implementing new features, fixing bugs, and writing unit and acceptance tests. On feature that I worked on involved being able to quickly unlock the iOS app using a PIN. From a "backend" point-of-view, each employee would need to have the ability to set, modify, and delete their own PIN. There would also need to be a way that the iOS app can validate if the inputted PIN is correct. Therefore, I added a new column to the SQL table that held employee credential information that would store a hashed version of an employees PIN. Tulip's infrastructure is set up such that there are two databases, one for general information (product information, store information, non-sensitive employee information), and a second for permission/credential information. To accommodate this, there are also two different API's (one for each database). One API is written in PHP (non-sensitive data) and the other is written in Go (credential data). The mobile app always uses the PHP API to make its requests where it is then expected that API will make a request to the Go API if needed.

 

Therefore, to implement the PIN feature I first had to create 2 new PHP endpoints; one to delete a PIN, and one to to validate a PIN. To set/change a PIN, I took advantage of an existing "update" endpoint that allows you to send all the employee attributes you would like to change in the body of a PUT request. Because PIN's had to be stored in the credential database, I also had to create 2 new Go endpoints (similar to the PHP endpoints I added). Overall, the network requests looked like this:

​

​

​

​

iOS App

iOS App

(UPDATE) Set PIN

(POST) Validate PIN

(DELETE) Delete PIN

Send Pin

pin_set

200/401

Send Pin and username

200/401

Send employee ID

PHP API

Send Pin

pinSet

200/401

Validate  bpdy

200/401

Send employee ID

Go API

Hash and Save Pin

Unhash employee pin; compare to pin passed in body

Delete PIN

database.jpg

Go Database

Also, Tulip originally had one database that stored everything (the database used by the PHP API). When I joined the company in May, the second database (Go API) had already been created; but because of how large the codebase is, not all the legacy credential/permissions related code (that pointed to the tables in the PHP API's database) could move over to the Go API's database. For example, if an employee was promoted to a Manager, their permissions would be changed through the PHP API and saved to its database. However, the Go database would not be updated. The end goal was to update the code such that both databases are updated, then at another point in the future, drop the table in the PHP database and only have the permissions table in the Go database (and follow the basic flow of the PIN diagram above where the PHP API calls the Go API). 

iOS App

Request permissions be updated for employee 

Permissions/roles updated (200)

PHP API

when-you-decide-to-delete-a-block-of-cod

Update permissions to "manager" for employee

Data saved

database.jpg

Go Database

Map data from PHP database into the Go database

database.jpg

Go Database

My task was to migrate all the legacy code that had to do with fetching and updating an employee's permissions/roles (for example, are they an employee or manager?) to use the new Go API; essentially deprecated the permissions/roles table in the PHP database. To flow would look similar to the first flow diagram I drew above (excluding the specific types of API calls). The most difficult part of this tasks (and perhaps obvious) was making sure that in the process of updating the PHP API any other systems that depend on the API would not break. Doing so required updating not only the API but also systems that used it. Overall, I deleted a lot of code and successfully removed all the references to the old table...or so I thought. There was one system that I never decided to run unit tests on (whoops). As it turns out, in the process of refactoring the code in one of the systems, I had removed some code that introduced a bug in a section of the system that I didn't realize used that code. Unfortunately it didn't get caught until the code made it into production so I definitely learned a lesson there! 

Go API

ABOUT THE JOB

This was my third work-term at Tulip. For my previous two terms I worked as an iOS Developer creating a mobile-point-of-sale app for Indigo. (You can read about my experience working in that position job        . Be sure to check out the "2018 Update" section!)

​

This Summer I worked as a Software Developer on the Platform team. Within this team I was part of the Authentication sub-team. The Platform team is responsible for all of the backend features that support the core framework in the iOS apps (for clients) as well as several online tools that help clients configure the app to their needs. The Authentication team is responsible for...authentication. More specifically, Tulip uses OAuth2 and SAML to handle user login/logout and API access tokens. The code base consists mainly of PHP and Go. Prior to starting this job I had no experience working with any of these languages in a workplace environment.

​

Throughout the four months, I worked on implementing new features, fixing bugs, and writing unit and acceptance tests. On feature that I worked on involved being able to quickly unlock the iOS app using a PIN. From a "backend" point-of-view, each employee would need to have the ability to set, modify, and delete their own PIN. There would also need to be a way that the iOS app can validate if the inputted PIN is correct. Therefore, I added a new column to the SQL table that held employee credential information that would store a hashed version of an employees PIN. Tulip's infrastructure is set up such that there are two databases, one for general information (product information, store information, non-sensitive employee information), and a second for permission/credential information. To accommodate this, there are also two different API's (one for each database). The Mobile API is written in PHP (non-sensitive data) and Authentication API is written in Go (credential/permission data). The mobile app always uses the Mobile API to make its requests where it is then expected that API will make a request to the Authentication API if needed.

 

Therefore, to implement the PIN feature I first had to create 2 new Mobile API endpoints; one to delete a PIN, and one to to validate a PIN. To set/change a PIN, I took advantage of an existing "update" endpoint that allows you to send all the employee attributes you would like to change in the body of a PUT request. Because PIN's had to be stored in the credential database, I also had to create 2 new Authentication API endpoints (similar to the Mobile API endpoints I added). Overall, the network requests looked like this:

​

​

​

​

iOS App

iOS App

(UPDATE) Set PIN

(POST) Validate PIN

(DELETE) Delete PIN

Send Pin

pin_set

200/401

Send Pin and username

200/401

Send employee ID

Mobile API

Send Pin

pinSet

200/401

Validate  bpdy

200/401

Send employee ID

Auth API

Hash and Save Pin

Unhash employee pin; compare to pin passed in body

Delete PIN

database.jpg

Auth Database

Also, Tulip originally had one database that stored everything (the database used by the Mobile API). When I joined the company in May, the Authentication API and database had already been created; but because of how large the codebase is, not all the legacy credential/permissions related code (that pointed to the tables in the Mobile API's database) could move over to the Authentication API's database. For example, if an employee was promoted to a Manager, their permissions would be changed through the Mobile API and saved to its database. However, the Authentication database would not be updated. The end goal was to update the code such that both databases are updated (blue, orange and grey arrows in the diagram below), then at another point in the future, drop the table in the Mobile API database and only have the permissions table in the Authentication database (blue and orange arrows only). The reason why we couldn't just drop the table in the Mobile API database is because there is a lot of custom code written for each client. Going through all that code to find how and where the table is being used would be very time consuming. By refactoring the legacy code in a two stage fashion, the first stage would allow old code to still work as if nothing had changed while also allowing other teams to slowly begin refactoring their code to accommodate the second stage which would drop the table completely. 

iOS App

Request permissions be updated for employee 

Permissions/roles updated (200)

Mobile API

Data saved

Update permissions in Auth 

database

Save new permissions in Mobile 

database after saved in Auth database

database.jpg

Mobile

Database

Auth API

Save new permissions to database

database.jpg

Auth Database

when-you-decide-to-delete-a-block-of-cod

My task was to migrate all the legacy code (within the Platform team's codebase) that had to do with fetching and updating an employee's permissions/roles to use the new Authentication API; essentially deprecating the permissions/roles table in the Mobile API database. To flow would look similar to the first flow diagram I drew above (excluding the specific types of API calls). The most difficult part of this tasks (and perhaps obvious) was making sure that in the process of updating the Mobile API, any other systems that depended on the API would not break. Doing so required updating not only the API but also systems that used it. Overall, I deleted a lot of code and successfully removed all the references to the old table...or so I thought. There was one system that I never decided to run unit tests on (whoops). As it turns out, in the process of refactoring the code in one of the systems, I had removed some code that introduced a bug in a section of the system that I didn't realize used that code. Unfortunately it didn't get caught until the code made it into production so I definitely learned a lesson there! 

GOALS

lock.png
UNDERSTAND OAUTH2

Being on the Authentication team, I wanted to understand how Tulip's authentication system worked. This may seem like an obvious goal, but as someone who had only done iOS development prior to this job, I never had any exposer to how authentication systems actually work under the covers.

 

A lot of the bugs I worked on involved having to follow the code through a login and logout sequence which gave me perfect opportunities to learn about the system.

​

At first, following the path seemed like an impossible task given how many components there are to OAuth2. However, after spending some time setting breakpoints and reading through the code, it started to make sense. By the end of my work-term, whenever a bug related to the authentication system was assigned to me, I was able to find the source of the problem in a reasonable amount of time.

​

Overall, I believe I accomplished my goal to understand OAuth2. I understand the purpose of consent id's, the different types of tokens (id, access, and refresh) and how they are they are generated.

checklist.png
TEST
TEST
TEST

If you've read my report about working on the Indigo project las year, one of my goals was to "Access Risk". The purpose of that goal was to avoid creating bugs when refactoring code by evaluating everywhere that uses the code and make sure to test those areas.

 

Building off this goal, this year I wanted to force my self to create unit tests for every new feature or modification I implemented. In May, I would often forget about writing unit tests until my team reminded me. By the end of my term in August, I was writing several unit tests which provided thorough code coverage. For example, when I implemented the PIN login feature, I created 20 tests that covered situations where the API request would succeed or fail. Also, when I refactored the legacy credentials/permissions code I added to the existing tests to improve the code coverage.

​

Even though there were times where I either didn't test enough or didn't right a unit test for a scenario I didn't think of, overall I think I'm heading in the write direction in terms of getting into the habit of consistently writing and running unit tests.

speech.png
COMMUNICATE CLEARLY

Being able to explain what I'm working on has never been a strength of mine. I'll always stutter, or explain my work in a really confusing way. Personally I've always found visuals help explain my points.

​

For this reason, my final goal for this work term was to be able to explain what I was working on clearly and concisely at each scrum meeting.

​

To accomplish this, prior to each scrum I planned out what I wanted to say rather than going into the scrum thinking on the spot. Sometimes I had to clarify what I meant when I said something but as the months went on I found my self getting better at getting my points across.

​

Also, when I implemented the PIN login feature, I had to do a code walkthrough and demonstration for the Security Team Lead. Doing this allowed me to see how well I can communicate how my code functions while also practicing how to do demonstrations. At the end of the meeting the team lead understood what I was saying and I was able to answer all his questions.

​

I believe I have accomplished this goal; however, I would like to continue working on this skill to keep improving.

Goals

CONCLUSION & ACKNOWLEDGMENTS

My four months at Tulip provided several learning experiences that I will be able to use in future jobs. Having never worked in a backend position before, the job was challenging at times, however my team really helped me out along the way. Also, being able to gain experience in a backend environment has allowed to understand how frontend and backend systems tie together. Between this and my previous work terms at Tulip, I have be given several opportunities (such as working directly with clients, and work on different parts of the companies infrastructure) that have definitely improved me as a developer and for that I thank Tulip.

​

I would like to thank my team lead, Phil, who helped me understand how all the different systems tied into each other and always provided constructive criticism on where my code could be improved.

​

I would also like to thank the entire Platform team as a whole. Michael, Chris, Mohammad, Haisin, Dylan, Blaise, and Shaghayegh were all awesome to work with and always willing to help out.

​

Finally, I said this in my last report and I'll say it again: To any co-op students reading this I would definitely recommend you apply to Tulip, no matter the position. The culture at Tulip is awesome and everyone wants you to succeed!

Conclusions
bottom of page