Skip to content

Instantly share code, notes, and snippets.

@dradford
Last active October 28, 2019 02:37
Show Gist options
  • Save dradford/bc7734953071bbaf7357174e4f36554e to your computer and use it in GitHub Desktop.
Save dradford/bc7734953071bbaf7357174e4f36554e to your computer and use it in GitHub Desktop.
Catapault Tagging API

Catapult™ Challenge

Catapult™ is a proprietary, state-of-the-art system for selling and shipping cats to cat enthusiasts worldwide.

This coding challenge consists of three options based on different levels of experience and time constraints. Feel free to undergo any of the following challenges, and if you feel you have enough time, you're more than welcome to complete more than one.

Your challenges, should you choose to accept them:

  1. Basic cat breed tagging API

This challenge should take a senior engineering applicant about 2 hours, with passing tests.

  1. Rails engine for a generic tagging API

This challenge should take a senior engineer about a day to complete. If you would like to undergo this challenge, we'll be a lot more flexible with time constraints and psuedocode.

This challenge requires some knowledge of more advanced Rails concepts, such as engines and railties. If you throw in some cool Ruby metaprogramming, we'll probably faint with excitement.

  1. Cat breed de-dupli-cat-or

The final challenge is more open-ended and is intended for applicants who really want to flex their creativity. It's intended to be more of a conceptual challenge, but it should obviously lead towards a technical solution.

This challenge could take a few hours, or it could be a very efficient algorithm that you crank out in 15 minutes off the top of your head. It really depends on your knowledge and skill level.

Overview

Building a Folksonomy of Cats

"A folksonomy is a user-generated system of classifying and organizing online content into different categories by the use of metadata such as electronic tags." -- Google

A huge part of why Catapult has been such a hit with feline enthusiasts over the years is its revolutionary Auto-Suggestion Engine™, which matches certain cats with potential owners.

A diehard Catapult poweruser has messaged us with an idea to add cat tagging. Our resident Product Manager, in collaboration with our chief data scientist, thinks this would also be a great way to improve the Auto-Suggestion Engine. One of our senior engineers, Karen, suggested that we build a folksonomy categorization of different types of cats, and allow tagging each category with certain character traits. We all think this is a marvelous idea.

Unfortunately, Karen has just left for three weeks vacation in the Bahamas, and we desperately need to find someone who can build our cat-egorization system. We're hoping it's you!

Cat Folksonomy Epic

Problem Statement

Our cat folksonomy will be a way to categorize and tag cats. Each "entity" will be a cat breed, and each "tag" will be a character trait. A basic example of how this should work is described below:

Basic System
Entity (cat breed):
  |
  -- Tags (traits)
Concrete Example
American Bobtail
  |
  -- affectionate
  -- low shedding
  -- playful
  -- intelligent

Cymric
  |
  -- affectionate
  -- has no tail
  -- friendly

Norwegian Forest Cat
  |
  -- low shedding
  -- pet friendly
  -- knows kung fu
  -- climbs trees

Tasks / Challenges

1. Basic cat breed tagging API

Implement the above folksonomy system as a JSON API in Rails.

API route hints

For this first challenge, we've provided some hints for tagging API endpoints. If you'd like to propose a different architecture for the routes, feel free to do so with a clear explanation of your reasoning.

Breed CRUD
POST /breeds

- Breed Name, e.g. 'Norwegian Forest Cat'
- Tags, e.g. ['Knows Kung Fu', 'Climbs Trees']

GET /breeds

- retuns all breeds

GET /breeds/:breed_id

- returns the breed and all the tags belonging to it

PATCH /breeds/:breed_id

- Updates the breed and it's tags (overwrite tags, don't merge)
- Breed Name, e.g. 'Norwegian Forest Cat'
- Tags, e.g. ['Knows Kung Fu', 'Climbs Trees']

DELETE /breeds/:breed_id

- Removes the breed
- When it comes to tags of deleted breeds, please work out a way to ensure there aren't orphaned tags left in the system that can't be deleted.
Tag CRUD
GET /breeds/:id/tags

- Gets tags on a breed

POST /breeds/:id/tags

- Replaces tags on a breed
- Tags, e.g. ['low shedding', 'pet friendly']

GET /tags

- returns all tags in the system

GET /tags/:id

- returns a tag

PATCH /tags/:id

- updates a tag

DELETE /tags/:id

- deletes the tag and all associations to breeds

Breed & Tag Stats

GET /breeds/stats
- Retrieves statistics about all breeds
- breeds: [
    {
      id: 1,
      name: 'American Bobcat',
      tag_count: 4,
      tag_ids: [1, 2, 3, 4]
    },
    {
      id: 2,
      name: 'Cymric',
      tag_count: 3,
      breed_ids: [1, 4, 5]
    }
  ]


GET /tags/stats

- Retrieves statistics about all tags
- tags: [
    {
      id: 1,
      name: 'has no tail',
      breed_count: 1,
      breed_ids: [2]
    },
    {
      id: 2,
      name: 'affectionate',
      breed_count: 2,
      breed_ids: [1, 2]
    }
  ]

Considerations:

  • the above specification is a guide. If you have ideas that could improve the usability of the API please feel free to adjust the spec and highlight your reasoning in the readme.
  • if you're unsure about anything, please ask.
  • N+1s are bad

2. Rails engine for a generic tagging API

Our business is branching out into non cat-like animals (amaze!!!). Although the product is still in stealth mode, our PR department has cleared us to disclose that we've acquired an online dog delivery service called "Bone Thrower". Luckily for us, the crack BT engineering team were on point with their Rails upgrades, and their platform, like ours, runs on Rails v5.1.2. Thanks to their great foresight, we can easily extract our tagging system into an engine that can be shared across both applications.

We'd like you to extract the solution from task 1 into a gem that can be included in both systems. The idea is to create a Generic Tagging API that can store, retrieve, delete and report on the usage of tags across multiple entity types.

Our CTO has also said that if you build it well, we will release it as an open source project under the MIT license to accept contributions from the community.

Your task is to reimplement the tagging API described in the first challenge as a Rails engine, providing a generic tagging API that can be easily incorporated into multiple Rails projects.

Some guidelines:

  • After adding the gem to a new project, you should be able to install the tagging tables using bin/rails generate tagger:install and then bin/rake db:migrate
  • The tagger should be a module that can be added to any model using an acts_as_taggable-style syntax. Think about replacing Breed with Entity.
  • You can choose between a minimal rack-test + model testing strategy, or a more fleshed-out rspec-rails testing strategy.
  • Your API should be route-mountable, e.g. in your routes file you just need to use mount_tagger

We'd love to see a fully working and tested engine, but we understand that this might be difficult to implement in a reasonable amount of time. If we can see that you've attempted to implement all aspects, but just came short of getting it going, please let us know (we're very understanding of busy schedules.)

3. A Cat Breed De Dupli-cat-or

You've been here at Catapult for a few months, you've published an awesome tagging system that's humming along in production, and you're super proud to have it out there in the open source community as the top contributor. Your GitHub account is even marked as the CODEOWNER for the .gemspec! (Remember that time someone tried to add actionview as a runtime dependency for your API?)

Only problem is, after running the tagging system for a few months, the team has discovered that a lot of breeds have been duplicated endlessly with slightly different spellings.

Absolutely no shame in that. We learnt some valuable lessons in shipping the tagger quickly, but now it's time to iterate and clean things up a bit.

Your goal is to write a small program to assist our team in identifying whether a new cat breed is unique or a duplicate.

We're not necessarily expecting a functional piece of code, but to we'd like you to demonstrate how you'd tackle the problem of deduplication. With that in mind, you're encouraged to explain your methodology, either through concise code or explanatory comments. Feel free to stub out anything you need, and don't be afraid to explore creative or experimental solutions. We want to see what you're capable of.

What we're looking for:

  • You followed directions and used your best judgement to ensure a correct solution.
  • You explained your reasoning in README.md
  • Any code you've written is understandable and easy to read.
  • You've followed community standards and conventions relating to Ruby and Rails development.
  • You've written the code as though it will be released to production.
  • If you've written tests, we can see that all of the tests pass.

Once you’re done, please push your solution GitHub and add @bugcrowd/interviewers as a collaborator.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment