---
# System prepended metadata

title: MYSA Technical Assessment
tags: [Assessment, Document]

---

---
title: 'MYSA Technical Assessment'
disqus: mysa
---

MYSA Technical Assessment
===
**Jaehyun Park** (5/8/2020 5pm to 5/10/2020 5pm ET)

## :boom: NOTICE :boom: 
* **This document contains updates after deadline.**
* **Please, use the offline version submission for evaluation.**

## Table of Contents

* [Question 1](#Question-1)  
* [Question 2](#Question-2)  
* [Question 3](#Question-3)  
* [Question 4](#Question-4)  
* [Question 5](#Question-5)  
* [Question 6](#Question-6)  

Prologue
---
Congratulations, you have been selected to design Mysa’s next product: a smart toaster. All of
the following questions relate to tasks you will have to do as the lead (and only) designer.

Question 1
---

### 😵 Question
Make a complete list of product features, giving a brief description of each. Categorize
each of them as “required”, “added value”, or “exploratory”. Include both hardware and
software features.

### 😊 Solution
**MYSA FreshPOP Toaster**
#### 1. Main Idea

:::info
#### Nothing can't beats freshly baked bread. **FreshPOP** gives a new life into the dry dry dying breads and turns it into moistness as if it just got baked.

#### **Air fryer** is not really a fryer, but we call it a fryer. This is not a toaster, it's a electric grill plus a steamer, but we call it a **MYSA FreshPOP Toaster**.
:::

#### 2. Features
* Hardware / Software Common Features (Required)
    * Select Bread Status (Button)
        * Frozen
        * Normal
    * Select Bread Type (Button)
        * White Bread
        * Artisan Bread
        * Buns
        * Tortilla
        * Bagel
    * Select Toast Mode (Button)
        * Moist : Only Stream mode
        * Soft : Steam + Grill mode
        * Crispy : Only Grill mode 
    * Toast it! (Button)
* Software Features (Added Value)
    * Beyond Bread
        Warm up leftovers beside Breads.
        A lot of pre-settings for Beyond Bread recipes can be downloadable through the internet.
        * Cooked Meet
            * e.g. Bacons, Pulled pork
        * Cooked Rice
            * e.g. cold fried rice leftover
        * Vegitable
            * e.g. any steamed or grilled vegitables
        * Others
            * e.g. Pizza leftover

#### 3. Concept Image
![](https://i.imgur.com/46NUgHo.jpg)


Question 2
---

### 😵 Question
Sketch a wireframe UI concept for a mobile app that will control the smart toaster. Keep
your wireframes to the most important screens in the app (3 or less). You can include
brief explanations where necessary. Create these sketches with pencil and paper, then
take a picture or scan to submit with your other answers.

### 😊 Solution
![](https://i.imgur.com/PPAahfK.jpg)

**MAKE your FROZEN > BAGEL > MOIST!** :bread: :doughnut:
<img src="https://i.imgur.com/LXl81OV.jpg" alt="vi three modes" width="300"/>  

**UI concept version2** (This is **added** at 5/11/2020 **after assessment deadline**)
(I did it just for fun after deadline. it shouldn't be considered for assessment)
![](https://i.imgur.com/0OvTHOB.jpg)

Question 3
---

### 😵 Question
You managed to sucker someone into helping you on this project and they wrote a function to read the toaster’s settings from a SQL database in JavaScript, but they didn’t provide any unit testing for their code. Describe the set of tests you would create based on the function outlined below, and write code for any one of the tests.
```javascript
/*
@brief This function loads a toaster’s settings from the database. If
there is an error, an error will be returned along with default
settings from the getDefaultSettings() function. If there are no
settings, it will return the default settings from the
getDefaultSettings() function.
@param id - unique id of the toaster
@param callback - the callback function takes (error, data) objects.
*/
function readToasterSettings(id, callback) { ...
```
### 😕 Solution
```javascript
const ERROR_MESSAGE_ID_IS_NULL = "ID can not be a null"
const ERROR_MESSAGE_ID_DOES_NOT_EXIST = "ID does not exist"

function Should_ReturnDefaultSettings_IfIdIsNull(testId) {
    readToasterSettings(null, (error, data) => {
        if ((error === ERROR_MESSAGE_ID_IS_NULL) && (isDefaultSettings(data))) {
            return logTestPassed(testId)
        } else {
            return logTestFailed(testId)
        }
    })
}
const Should_ReturnDefaultSettings_IfIdDoesnotExist = (testId) => { }

const unitTestHandlers = {
    100: Should_ReturnDefaultSettings_IfIdIsNull,
    101: Should_ReturnDefaultSettings_IfIdDoesnotExist,
    // ...
}
const unitTestById = (id) => unitTestHandlers[id](id)
const unitTestFull = () =>
    Object.entries(unitTestHandlers).forEach(([key, value]) => value(key))
    
unitTestFull()
```
I'm pretty not sure I did right with this question since I don't have experience with unit testing.
Hope that I can learn this and get better soon!

Question 4
---

### 😵 Question
You have decided to use semantic versioning for all of your applications. For feature
compatibility, you have to compare versions of mobile app to anything server-side. To
save time in the app you “found” some JavaScript code on the internet that will compare
version strings directly - but it doesn’t work properly. Do a code review on the following
to find functional issues as well as style problems. You do not have to provide a working
solution.
```javascript
// This function compares version strings (ex.major.minor.patch)
//Returns:
// -1 if a < b
// 1 if a > b
// 0 if a = b
function compareVersionAToVersionBAndReturnGreater(A, B) {
    const i, d, x;
    var regExNoDecimals = /(\.0+)+$/;
    let segmentsA = a.replace(regExNoDecimals, '').split('.')
    let segmentsB = b.replace(regExNoDecimals, '').split('.')
    for (i = 0; i < Math.min(segmentsA.length, segmentsB.length); i++) {
        d = parseInt(segmentsA[i], 10) - parseInt(segmentsB[i], 10);
        if (d) {
            return d;
        }
    }
    return 0;
} 
```

### 😊 Review
#### 1. Input parameter mismatchs. A and B should be a lowercase.
#### 2. Variable i and d are not constants. It should be declared with let.
#### 3. Variable x should be removed.
#### 4. Variable regExNoDecimals should be immutable. Declaring with const is requried.
#### 5. Variable segmentsA and segmentsB are also constants. It should be declared with const.
#### 6. Conditional statement "if (d) {.." has bad readability. 
> Given condition should be explained well with better name (e.g. 'distance' instead just 'd'), sub-routine (e.g. isValidDistance(d)), or explicit use of comparison operator.
#### 7. Following the given comments, 'return value' looks it is supposed to be -1, 1, or 0. 
> But values which is less than -1 or bigger than 1 can be returned.
**e.g.** v2.1.1 and v2.1.10 => it returns -9, but following writer's intention that can be inducted from his comments, it should be -1
#### 8. Defensive coding that inserts zero value in an empty field is required to prevent an error from min length segment.
> **e.g.** 2.1 and 2.1.3 => it returns 0, but has to be -1
#### 9. The comparison routine should be updated to fully satisfy the following requirements (_ordering rules **3,5,6** below are not supported currently_), including <pre-release> Identifier.
> At least, it should be announced that it doesn't support <pre-release> identifier of Semantic Versioning.
:::info
**Semantic Versioning 2.0.0** [link](https://semver.org)
    
1. Precedence must be calculated by separating the version into major, minor, patch and pre-release identifiers in that order.
2. Precedence is determined by the first difference when comparing each of these identifiers from left to right as follows: Major, minor, and patch versions are always compared numerically. 
**e.g.** 1.0.0 < 2.0.0 < 2.1.0 < 2.1.1. 
3. When major, minor, and patch are equal, a pre-release version has lower precedence than a normal version
**e.g.** 1.0.0-alpha < 1.0.0. 
4. Identifiers consisting of only digits are compared numerically
5. Identifiers with letters or hyphens are compared lexically in ASCII sort order. 
6. Numeric identifiers always have lower precedence than non-numeric identifiers.
**e.g.** (rule 4-6) 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0
:::


Question 5
---

### 😵 Question
You feel like you need to brush up on some JavaScript training before you
continue: go to https://play.elevatorsaga.com/ and create a solution that
solves the first 4 challenges. Provide heavily commented code to explain
your logic and why you used any JavaScript constructs that improve
performance.

### 😊 Solution
```javascript
{
  /**
   Solution:
   1. The floor number is stored into waiting list once passenger press
      the button calling the elevator. (handlers.floor.button_pressed)
   2. If elevator Queue is empty, elevator goes to the floor number 
      stored in waiting list. (handlers.elevator.idle)
   3. Elevator stops at the floor if the floor number is in the waiting 
      list. (handlers.elevator.passing_floor)
   4. If button is pressed in elevator, the floor is inserted in an 
      efficient position of elevator queue. (handlers.elevator.floor_button_pressed)
   5. The floor number is removed from waiting list once elevator stops 
      at each floor. (handlers.elevator.stopped_at_floor)
   */
  init: function(elevators, floors) {
    // Set max load
    const FULL_LOAD = 0.8;
    
    // The list of floor with people want to get on the elevator
    let waitingFloorList = [] 

    const removeFloorFromWaitingList = function (floorNumber) {
      // Remove the floor
      waitingFloorList = waitingFloorList.filter(f => f !== floorNumber)
    }

    function isPassengerOnFloor(direction, floorNumber) {
      // Check passengers on the floor
      return waitingFloorList.includes(floorNumber)
    }

    const handlers = {
      floor: {
        button_pressed: function () {
          // Add floor to waiting list.
          waitingFloorList.push(this.level);
        },
      },
      elevator: {
        idle: function () {
          if (waitingFloorList.length > 0) {
            // Go to the floor
            const floorNumber = waitingFloorList[0];
            removeFloorFromWaitingList(floorNumber);
            this.goToFloor(floorNumber);
          }
        },
        passing_floor: function (floorNum, direction) {
          const isElevatorFull = () => this.loadFactor() >= FULL_LOAD;
          const shouldStop = !isElevatorFull() &&
                              isPassengerOnFloor(direction, floorNum);
          if (shouldStop) {
            // Break!
            this.destinationQueue.unshift(floorNum); // add front
            this.checkDestinationQueue();
          }
        },
        floor_button_pressed: function (floorNum) {
          // Where should we insert this floor?
          const index = this.destinationQueue.findIndex(f => f > floorNum)
          if (index > 0) {
            // Yeah, we found a good position
            this.destinationQueue.splice(index, 0, floorNum) // insert at index
          } else {
            // Nope, just attach it to the rear
            this.destinationQueue.push(floorNum); // add rear
          }
          // We changed Q. Confirm it!
          this.checkDestinationQueue();
        },
        stopped_at_floor: function (floorNum) {
          // We done it! Don't let other elevators come here
          removeFloorFromWaitingList(floorNum);
        }
      }
    }

  // floor handle
  floors.forEach(function (floor) {
    floor.on('up_button_pressed down_button_pressed', handlers.floor.button_pressed)
  });

  // elevator handle
  elevators.forEach(function (elevator) {
    elevator.on("idle", handlers.elevator.idle);
    elevator.on("passing_floor", handlers.elevator.passing_floor);
    elevator.on("floor_button_pressed", handlers.elevator.floor_button_pressed);
    elevator.on("stopped_at_floor", handlers.elevator.stopped_at_floor)
  });
 },
 update: function(dt, elevators, floors) {
 }
}
```

**bug fix**
* **5/12/2020** - fixed the issue that idle elevator didn't move 
(I did it because I just noticed it by chance today. it shouldn't be considered for assessment)
    * [patch](https://github.com/jaeyp/elevator-saga/commit/fd49bbc6a7558312c49d77ad7a61f3311582ddaf)
    * [full source](https://github.com/jaeyp/elevator-saga/blob/master/solution.js)  


Question 6
---

### 😵 Question 
Create a name for your product. Bonus points for a logo or slogan.

### 😳 Solution
#### Product Name: **MYSA FreshPOP Toaster**
#### Logo: 😣 oh, drawing...![](https://i.imgur.com/67YF0Ce.jpg)

#### Slogan: 😱 oh, english... "I'm not dry anymore"???



Epilogue
---

#### Thanks in advance for your time for reviewing! 
#### I look forward to hearing from you.

Jaehyun Park

###### tags: `Assessment` `Document`
