Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 96 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

## 1. Deduplication algorithm

Using a language of your choice, implement a function to deduplicate a list of words,
so that, the function receives the list as an argument and returns the list without the
Using a language of your choice, implement a function to deduplicate a list of words,
so that, the function receives the list as an argument and returns the list without the
duplicates. Here's an example in Javascript

```js
Expand All @@ -18,20 +18,25 @@ NB: the order of the output list does not matter.
There are many ways to do this - feel free to google your options. We want to see:

1. The function in syntactically correct (and readable) code.
1. Three methods in ``app.component.ts`` file
2. An explanation of why you would choose this particular method.
1. ``deduplicateMethod1()`` is a preferred one, (the most clean as well)
3. A unit test!
1. Available in ``app.component.spec.ts``

Results in ``/tech-test/deduplication-app`` which is an Angular v12 app with Unit-tests

## 2. Booking system data schema

Imagine you are implementing a booking system for a peer2peer car share.
Imagine you are implementing a booking system for a peer2peer car share.

User A, "Lender" needs to specify when their car is available, while user B, "Borrower"
needs to be able to reserve the car at their preferred time. A car can only be lent to
User A, "Lender" needs to specify when their car is available, while user B, "Borrower"
needs to be able to reserve the car at their preferred time. A car can only be lent to
one person at a time.

What data schema would you need to store in order to support these use cases? Feel free
to demonstrate a solution in your favourite datastore. The solution should support a simple
query to show what cars are available at a given time (even if some bookings have already
What data schema would you need to store in order to support these use cases? Feel free
to demonstrate a solution in your favourite datastore. The solution should support a simple
query to show what cars are available at a given time (even if some bookings have already
been made). You don't have to do it relational schema, but you have to show how the query
would look.

Expand All @@ -42,7 +47,6 @@ Here's an example in psuedocode to get you started:
| car |
+----------+
| id |
| user_id |
| metadata |
+----------+

Expand All @@ -54,20 +58,73 @@ Here's an example in psuedocode to get you started:
+----------+

Relations:
car belongs to user
+---------------------+
| car_belongs_to_user |
+---------------------+
| id |
| user_id | (fk user_id -> user.id)
| car_id | (fk car_id -> car.id)
| bookingStartDate |
| bookingEndDate |
| status | ('BOOKED', 'CANCELLED', 'COMPLETED')
| metadata |
+---------------------+

CREATE TABLE IF NOT EXISTS car (
id uuid NOT NULL PRIMARY KEY,
metadata JSONB NOT NULL
);

CREATE TABLE IF NOT EXISTS users (
id uuid NOT NULL PRIMARY KEY,
metadata JSONB NOT NULL
);

CREATE TYPE BOOKING_STATUS AS ENUM ('BOOKED', 'CANCELLED', 'COMPLETED');

CREATE TABLE IF NOT EXISTS car_belongs_to_user (
id uuid NOT NULL PRIMARY KEY,
user_id uuid NOT NULL,
car_id uuid NOT NULL,
bookingStartDate date NOT NULL,
bookingEndDate date NOT NULL,
status BOOKING_STATUS NOT NULL,
metadata JSONB NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (car_id) REFERENCES car(id)
);

As input user would have to provide 2 dates (bookingStartDate and bookingEndDate).
Prerequisite that must be fulfilled: 'bookingEndDate' > 'bookingStartDate'
Example query:

SELECT * FROM car as c
WHERE c.id NOT IN (
SELECT cbtu.car_id from car_belongs_to_user cbtu
where $INPUT_START_DATE <= cbtu.bookingEndDate
and $INPUT_END_DATE >= cbtu.bookingStartDate
and cbtu.status = 'BOOKED'
)

```
There are many ways to do this - feel free to google your options. We want to see:

1. Some kind of schema (e.g. sqldump, JSON)
1. ``See above DB table schema``
2. Example of how the query would look
1. ``See above example query``
3. Why is this solution better than some alternative?

1. ``I have adjusted the given schema because then we don't need to edit "CAR" entity.
This way we can also keep track which cars are the most popular, which bookings were successfully completed and
how long they have lasted, also which were cancelled.
It is always good idea to keep details of relation outside of their entities.
Also this relationship could be considered as Many:Many``

## 3. FrontOps

You have a frontend app written in ReactJS and you are preparing it for production. The app
needs to call an API server with a FQDN configured in the variable API_BASE_URL. There
will be a production deployment and a staging deployment
needs to call an API server with a FQDN configured in the variable API_BASE_URL. There
will be a production deployment and a staging deployment
for demos/testing. How would you deploy the frontend so that the same build (minified JS, CSS
and HTML) can be used in production and staging deployments?

Expand All @@ -77,6 +134,32 @@ We want to see:
2. A list of steps you need to take to change the FQDN of the API (API_BASE_URL) for production or staging
3. How would you handle new versions of the API?

Answers:
1.
1. In best case scenario these variables should be set on the SPA build time within CI/CD pipeline. Based on the environment
where the pipeline/job is executed app could be build under specific predefined config and use the proper set of environment
variables.
2. In your case study, it's required to be added after the app has already been built and (app is bundled, code minified and so on ...)
In such case, React has built-in environment variables that are accessible during the runtime.
Here is an interesting link on how custom env variables could be introduced to the React app (https://create-react-app.dev/docs/adding-custom-environment-variables/)
3. In the markup or JS files such variable is accessible via the following: "process.env.NODE_ENV"
4. Additionally, using react-scripts@0.2.3 or higher will let your React app consume environment variables defined locally in .env file. Those variables need to be prefixed with "REACT_APP_"

2.
1. Create .env file if not existing
2. Add environment variables that are needed (e.g. API_BASE_URL_STAGING, API_BASE_URL_PROD)
3. Check on which environment the app is running with
1. const baseApiUrl = process.env.NODE_ENV === 'production' ? process.env.API_BASE_URL_PROD : API_BASE_URL_STAGING
3. It depends, API should use semantic versioning as in here (https://semver.org/) where MINOR and PATCH versions should not have a major impact on the application.
Each release should have it's list of release notes so API consumers are aware of possible risks/changes after update.
A new API version should still offer backward-compatibility, but mark certain parts as deprecated which will be removed in one of the next versions
The API version could be reflected in the URL looking something like this:
1. https://n3xtcoder.org/api/v1.0.0/ (initial release)
2. https://n3xtcoder.org/api/v1.0.1/ (patch release)
3. https://n3xtcoder.org/api/v1.2.4/ (minor release)
4. https://n3xtcoder.org/api/v2.0.0/ (major release that could have big impact on the app usage - still offering support for v1.x.x features)4
5. https://n3xtcoder.org/api/v3.0.0/ (another major release that removed deprecated parts of code - this will now require a certain action/refactoring on the side of API consumers)

## Submitting your solution

Please submit your solution as a PR including some nice commits for challenge 1 and the rest in Markdown.
17 changes: 17 additions & 0 deletions deduplication-app/.browserslistrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries

# For the full list of supported browsers by the Angular framework, please see:
# https://angular.io/guide/browser-support

# You can see what browsers were selected by your queries by running:
# npx browserslist

last 1 Chrome version
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major versions
last 2 iOS major versions
Firefox ESR
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.
16 changes: 16 additions & 0 deletions deduplication-app/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Editor configuration, see https://editorconfig.org
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true

[*.ts]
quote_type = single

[*.md]
max_line_length = off
trim_trailing_whitespace = false
45 changes: 45 additions & 0 deletions deduplication-app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.

# compiled output
/dist
/tmp
/out-tsc
# Only exists if Bazel was run
/bazel-out

# dependencies
/node_modules

# profiling files
chrome-profiler-events*.json

# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace

# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*

# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings

# System Files
.DS_Store
Thumbs.db
27 changes: 27 additions & 0 deletions deduplication-app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# DeduplicationApp

This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 12.1.2.

## Development server

Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.

## Code scaffolding

Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.

## Build

Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.

## Running unit tests

Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).

## Running end-to-end tests

Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.

## Further help

To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
114 changes: 114 additions & 0 deletions deduplication-app/angular.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"cli": {
"analytics": false
},
"version": 1,
"newProjectRoot": "projects",
"projects": {
"deduplication-app": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
},
"@schematics/angular:application": {
"strict": true
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/deduplication-app",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"inlineStyleLanguage": "scss",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.scss"
],
"scripts": []
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"outputHashing": "all"
},
"development": {
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"browserTarget": "deduplication-app:build:production"
},
"development": {
"browserTarget": "deduplication-app:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "deduplication-app:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"inlineStyleLanguage": "scss",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.scss"
],
"scripts": []
}
}
}
}
},
"defaultProject": "deduplication-app"
}
Loading