Front End Interview Question

lucvankerkvoort

Luc van Kerkvoort

Posted on July 14, 2022

Front End Interview Question

We as programmers lead a hard life. Especially when it comes to the interview process. There are many obstacles we have to face to get a new job, which is never fun to do.

I bet all of you reading this are excellent programmers, but a lot of us have a problem when we get put on the spot... performing under pressure is not our forte. This is why we didn't become olympic swimmers, or deep sea divers...

All jokes aside I think it is important for us to document the hoops we have to jump through to get a job. That is why I wrote this article about a take home assignment I once received from a company.

The Assignment

I received the following requirements

  • Create a button that once clicked showcases the current price of Bitcoin
  • After the button is clicked the buttons text changes from "get Bitcoin price" to "refresh Bitcoin price"
  • After the button is clicked it changes color from blue to purple
  • Once the button is clicked a field shows up with "Current price: " after a consecutive click a second field shows up with "Previous price: "

This was the entirety of the brief, the assignment had little to no restrictions to it. You can use libraries however you like them. You can use outside sources to fill in the code and you have 1 hour to complete it.

The Approach

I started thinking about how I wanted to structure the code keeping in mind best practices and going for a functional programming solution. In functional programming we break big problems down into modular solutions. This means we build functions that are reusable and pure

Logic

So I started dividing up the work and I came up with the following approach and pseudo code for the logic:

Button press

I'll use a useState to keep track of the button state.
This is also a value we can pass along to the button to change the color of it and use it to set the text for it

// Button press

const [isPressed, setPressed] = useState(false)
Enter fullscreen mode Exit fullscreen mode

API call

I'll create a modular API call for the bitcoin call with a try catch statement which will return an empty array so the page will still load even if the call fails.

// API call

const getBitcoin = async() => {
 try{
      fetch(url)
    } catch {
      return []
    }

}
Enter fullscreen mode Exit fullscreen mode

Setting Amount

thinking about this we need a data structure to keep track of the bitcoin prices. In my mind the best approach would be a Queue where a price comes in and we display it as current, then a second price comes in and current becomes the new price and the old price becomes the previous price and so on and so forth

// setting amount

const [bitcoinPrices, setPrice] = useState([])

const setAmount = (data = {}) => {
  const newPrices = [data, ...bitcoinPrices].slice(2)
  setPrice(newPrices)
}

Enter fullscreen mode Exit fullscreen mode

These will guide me into creating the application.

User Interface

Now We'll have to build out the UI for this application. Let me add that the UI looks kind of funky because there were no restrictions to what the UI looks like, this was purely a showcase of logic skills

  <div className="App">
      <button>
        {isPressed ? "refresh Bitcoin price" : "get Bitcoin price"}
      </button>
      <div>
        <div>
          {bitcoinPrice.map((value, i) => (
            <div key={i}>
              {i === 0 ? "Current price: " : "Previous price: "} {value}
            </div>
          ))}
        </div>
      </div>
    </div>

Enter fullscreen mode Exit fullscreen mode

as you can see I put in a ternary changing the text of the button from "get Bitcoin price" to "refresh Bitcoin price".

I am mapping the bitcoinPrice (state variable) to set the value. I'm using a ternary to decide the text in front of the value. If it is the index of 0 we set it to "Current Price" otherwise we set it to "Previous Price"

Extra curricular points

In this challenge I had to build it on my own machine while the interviewer was watching. I created a new React project using npx create-react-app. I got prompted the question why I used create-react-app.

These kind of questions are a great tool to share your knowledge. It is extra curricular points to know the answers to these kind of questions, so if you don't that is okay but here is an acceptable answer to the question

create-react-app is a package that presets an entire React application which installs babel which is a compiler used to parse JSX code to plain ES5 JavaScript, it installs webpack a bundler and presets it to bundle the application, installs React and presets the Virtual DOM, sets up testing with React testing library, so right out of the box we can start coding away.

The other good thing about it is that you can install and talk at the same time. Hopefully by the time you are done talking the installation will be complete.

The Execution

Under the watchful eye from my interviewer I started building out the application. first a draft version to get things started:


function App() {
const [isPressed, setPressed] = useState(false)
const [bitcoinPrice, setBitcoinPrice] = useState([])

const getBitcoin = async() => {
     try {
    const call = await fetch("https://api.coinbase.com/v2/prices/BTC-USD/buy", {
      method: "GET",
      authorization:
        "Bearer abd90df5f27a7b170cd775abf89d632b350b7c1c9d53e08b340cd9832ce52c2c",
    });
    const response = await call.json();

    return await response;
  } catch {
    return [];
  }
};

const setAmount = () => {
 const data = await getBitcoin()

  if(!data) return

console.log(data) 
// {"data":{"base":"BTC","currency":"USD","amount":"19891.09"}}

const {data: { amount }} = data

// New amount is pushed in front of the old amounts that have been deconstructed. 
// We then slice the array at 2 so we get rid of any old data we don't want to use anymore
const newPrices = [amount, ...bitcoinPrice].slice(2)

setBitcoinPrice(newPrices)

}



return(
  <div className="App">
      <button onClick={() => {
if(!isPressed) setPressed(true)
setAmount()
>
        {isPressed ? "refresh Bitcoin price" : "get Bitcoin price"}
      </button>
      <div>
        <div>
          {bitcoinPrice.map((value, i) => (
            <div key={i}>
              {i === 0 ? "Current price: " : "Previous price: "} {value}
            </div>
          ))}
        </div>
      </div>
    </div>
)

}

export default App

Enter fullscreen mode Exit fullscreen mode

Here I build the draft for the application. I felt like it is a lot of code on a single page but it was executing everything I needed for the logic, however on the User Interfaces the button wasn't changing color yet, so we had to tackle that with a library.

I asked the interviewer if I'm allowed to install libraries. He said yes, but you would have to explain the use case of the library.

I decided I wanted to implement styled-components, as a CSS library that allows me to send and use JavaScript right into my CSS. This is extremely handy if you have to set colors on elements using a ternary operator.

Styles

I created the following css file to style the Button and implemented the ternary operator to change the background color to purple after the button has been pressed, I also found that the list items were horizontally aligning to each other so I decided to use flexbox to fix that issue as you can see in the List component

import styled from "styled-components";

export const Button = styled.button`
  background-color: ${({ isPressed }) => (isPressed ? "blue" : "purple")};
`;

export const List = styled.div`
  display: flex;
  flex-direction: column;
`;
Enter fullscreen mode Exit fullscreen mode

with that out of the way I imported the components into the main file and I implemented the new styled components as shown below:

return(
  <div className="App">
      <Button isPressed={isPressed} onClick={() => {
if(!isPressed) setPressed(true)
setAmount()
>
        {isPressed ? "refresh Bitcoin price" : "get Bitcoin price"}
      </Button>
      <div>
        <List>
          {bitcoinPrice.map((value, i) => (
            <div key={i}>
              {i === 0 ? "Current price: " : "Previous price: "} {value}
            </div>
          ))}
        </List>
      </div>
    </div>
)
Enter fullscreen mode Exit fullscreen mode

Now I was happy about the styling and I could move forward with optimization of my code

Optimization

During the interview I started thinking whether my code was written with the best practices when it comes to writing functional programming. I did see a flaw in my setAmount function

const setAmount = () => {
 const data = await getBitcoin()

  if(!data) return

console.log(data) 
// {"data":{"base":"BTC","currency":"USD","amount":"19891.09"}}

const {data: { amount }} = data

// New amount is pushed in front of the old amounts that have been deconstructed. 
// We then slice the array at 2 so we get rid of any old data we don't want to use anymore
const newPrices = [amount, ...bitcoinPrice].slice(2)

setBitcoinPrice(newPrices)

}
Enter fullscreen mode Exit fullscreen mode

this function is not a pure function... Meaning with the same input we do not always receive the same output. It should also not be modifying any outside variables or have functions as children. I felt like this could be optimized by using composition

Composition or Piping

composing functions means we have a higher order function that executes a multitude of functions on a singular input. Meaning we give parameters to a function that then executes multiple functions in sequence utilizing the parameters, reading from right to left. e.g.

const purchaseItem = compose( 
  subtractFunds,
  emptyBasket, 
  moveToPurchase,  
  putInBasket)({name: "Laptop", price: 15})

Enter fullscreen mode Exit fullscreen mode

Piping is the same concept but then the other way around. Instead of right to left we go left to right

const purchaseItem = pipe( 
   putInBasket,
  moveToPurchase,  
  emptyBasket, 
subtractFunds,
 )({name: "Laptop", price: 15})

Enter fullscreen mode Exit fullscreen mode

I found a great solution to compose asynchronously. What this means is that I have created a compose function which takes in promises and converts those into actual data

export const compose =
  (...functions) =>
  (input) =>
    functions.reduceRight(
      (chain, func) => chain.then(func),
      Promise.resolve(input)
    );

Enter fullscreen mode Exit fullscreen mode

These powerful few lines create a composition HOF (higher order function) that resolves promises

First function
we give it x amount of functions in the first function of the chain, which we use a spread operator on. so we can have any amount of functions.

Second function
we take input in a second function, so we can curry the input on to the functions as seen in the example above.

Third function
this is what the actual function returns, it is a reducer that takes in chain and function. the chain is used to create a resolve for the functions, and resolves the given input through these chains.

I know right... take a breather after this one.

The Solution

The solution comes down to a couple of core concepts being applied to a core problem, as stated we had the following requirements:

  • Create a button that once clicked showcases the current price of Bitcoin
  • After the button is clicked the buttons text changes from "get Bitcoin price" to "refresh Bitcoin price"
  • After the button is clicked it changes color from blue to purple
  • Once the button is clicked a field shows up with "Current price: " after a consecutive click a second field shows up with "Previous price: "

The following paradigms are used to solve the issue:

  • modularization
  • functional programming
  • composing

here is a snapshot of the architecture implemented for this solution

Architecture

The following files are highlighted:

  • App.js - this stores the application
  • styles.js - this is holds our styled-components
  • /utils - folder with utility functions, in this case the compose function
  • /API - folder with API calls, in this case the bitcoin api

The reason I chose this file structure is that it gives room for growth, utility functions are really used a lot, storing these in an easy to reach folder is beneficial to a team working on an application. Setting up webpack to import from the /src folder is even better because these folders will be accessible anywhere instead of having the write relative paths.

let's take a close look at App.js

import React, { useState } from "react";
import { getBitcoin } from "./API";
import { compose } from "./utils";
import { Button, List } from "./styles";
import "./App.css";

function App() {
  const [hasBeenPressed, setPressed] = useState(false);
  const [bitcoinPrice, setBitcoinPrice] = useState([]);

  const storeAmount = ({ data }) => {
    if (!data) return;

    const { amount } = data;

    const bitcoinPrices = [amount, ...bitcoinPrice].slice(2);

    setBitcoinPrice(bitcoinPrices);
  };

  const bitcoinCall = compose(storeAmount, getBitcoin);

  return (
    <div className="App">
      <Button
        isPressed={hasBeenPressed}
        onClick={() => {
          if (!hasBeenPressed) setPressed(true);
          bitcoinCall();
        }}
      >
        {hasBeenPressed ? "refresh Bitcoin price" : "get Bitcoin price"}
      </Button>
      <div>
        <List>
          {bitcoinPrice.map((value, i) => (
            <div key={i}>
              {i === 0 ? "Current price: " : "Previous price: "} {value}
            </div>
          ))}
        </List>
      </div>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

as you can see I modularized some of the code, for example we are now importing the compose function as well as the API call for bitcoin, since the bitcoin API call returns a promise we use our special compose function to resolve that promise and pass on the data to the setAmount function.

  const [bitcoinPrice, setBitcoinPrice] = useState([]);

  const storeAmount = ({ data }) => {
    if (!data) return;

    const { amount } = data;

    const bitcoinPrices = [amount, ...bitcoinPrice].slice(2);

    setBitcoinPrice(bitcoinPrices);
  };

  const bitcoinCall = compose(storeAmount, getBitcoin);
Enter fullscreen mode Exit fullscreen mode

As you can see I utilized the styled components to create the button and the list components

Button component

<Button
        isPressed={hasBeenPressed}
        onClick={() => {
          if (!hasBeenPressed) setPressed(true);
          bitcoinCall();
        }}
      >
        {hasBeenPressed ? "refresh Bitcoin price" : "get Bitcoin price"}
      </Button>

Enter fullscreen mode Exit fullscreen mode

as you can see I'm passing on the hasBeenPressed to Button component, which is used in the styled component to change the background.I'm also using it to set the text utilizing a ternary operator.

List component


 <List>
          {bitcoinPrice.map((value, i) => (
            <div key={i}>
              {i === 0 ? "Current price: " : "Previous price: "} {value}
            </div>
          ))}
        </List>
Enter fullscreen mode Exit fullscreen mode

List is used for styling purposes only, making sure the div's are centered and in a column direction.

Helpers

I always like to create folders for my helper functions so it is structured and easily maintainable. These are the folders I created and I usually use the index.js format because these are easily accessible.

/utils

export const compose =
  (...functions) =>
  (input) =>
    functions.reduceRight(
      (chain, func) => chain.then(func),
      Promise.resolve(input)
    );

Enter fullscreen mode Exit fullscreen mode
/API

export const getBitcoin = async () => {
  try {
    const call = await fetch("https://api.coinbase.com/v2/prices/BTC-USD/buy", {
      method: "GET",
      authorization:
        "Bearer abd90df5f27a7b170cd775abf89d632b350b7c1c9d53e08b340cd9832ce52c2c",
    });
    const response = await call.json();

    return await response;
  } catch {
    return [];
  }
};

Enter fullscreen mode Exit fullscreen mode

named exports are easy to import again as well, it also separates the different functions instead of exporting default and having a load of different files.

Thank you

Thank you so much for reading this tutorial, I hope it has given you an insight into how to approach a problem like this.

I know this is an opinionated way of writing code but I believe that if you have a foundation that you are following and a good explanation to why you do the things you do, you are an excellent programmer.

if you want to connect you can do so here:

Github
Linkedin

đź’– đź’Ş đź™… đźš©
lucvankerkvoort
Luc van Kerkvoort

Posted on July 14, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related