Skip to content

Instantly share code, notes, and snippets.

@lazywithclass
Last active February 2, 2022 14:52
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lazywithclass/d5f1f510eaf5ce09c86b211b24c3668b to your computer and use it in GitHub Desktop.
Save lazywithclass/d5f1f510eaf5ce09c86b211b24c3668b to your computer and use it in GitHub Desktop.

1) Write an algorithm (choose the language you prefer) that given a character string, for instance {‘c’,’a’,’i’,’o’,’p’,’a’}, will print out the list of characters appearing at least 2 times. In this specific example, it would return {‘a’}. Afterwards, comment out the cost in terms of space and time.

// I've left out validation to concentrate on the algorithm itself, I hope it's ok

// O(n) time
// O(n) space
function charOccurrencies(string) {
  return string.split('').reduce((counts, n) => {
    counts[n] = counts[n] + 1 || 1
    return counts
  }, {})
}

// O(1) time
function print(o) { console.log(o) }

// O(n) time
function filterOccurrencies(occurrencies) {
  return Object.keys(occurrencies)
    .filter(char => occurrencies[char] >= 2)
}

// O(n) time
function printChars(string) {
  filterOccurrencies(charOccurrencies(string)).map(print)
}

// I would say in total it's O(n) time and O(n) space, as the worst case
// might have an input string containing all letters appearing at least twice 

printChars('caiopa')

2) Do you know what a unit test is? And an integration test? What is the difference? And a System Test?

A unit test is a mean to

  • document a piece of code
  • be protected when refactoring
  • obtain an overall design that's usually less coupled

A unit test focuses on a small portion of code, usually a function, a unit as the name suggests, it does not say anything about the correctness or usefulness of it when integrated with other units as it's usually used to drive development.

An integration test allows to fill this gap, making sure that different units are interacting with each other, to fullfill a greater purpose. It's also a useful aid when one has to interact with third party systems, for example a database, to make sure that the code is actually doing what it's been written for.

System tests are used to make sure the whole system will behave as expected in the final form, off the top of my head these could be

  • load tests - where the code is tested to see if it could handle the traffic with a reasonable response time
  • smoke tests - allow to see if the system is answering to external input, for example a login form could be smoke tested by seeing if it allows a user to login into the syste, if that does not work, then, for example, the whole deploy could be stopped, or testing should be focused on that part

3) You are reading a 16bit integer, composed of 2 bytes, from bytes over the network. What you should do to obtain the number from these 2 bytes? Which questions should you take into account?

I honestly have no idea.

4) Do you know design patterns? Describe one briefly.

I believe a widely used design pattern today is MVC, or one of its variants. It is strongly used in user interfaces because it allows to separate its main components in a simple way:

  • Model - where data is, this piece represents the problem domain usually it contains also the functions used to manipulate that data, or other times those reside in services
  • View - is the representation layer, in modern frameworks HTML5 is used to show components on a page
  • Controller - contains functions used to drive actions performed on the view to the model, for example you could have a function that validates and one submits a form to the server

The idea is to separate concerns to achieve loose coupling between components, this is good because for example one could easily swap a view for another.

5) Which is in your opinion the main problem that must be avoided when writing code? Explain why.

I believe the whitepaper "Out of the tar pit" got it perfectly right: complexity is the main problem.

Complexty is mainly the result of state and side effects used carelessly in a system. State handling and side effects should be confined in a different part of the system, one could see them as a disease that spreads tainting other parts.

By moving them into a separate zone it's easier to reason about the system as a collection of pure functions that deal with input and provide an output, referential transparency is key. Testing, and thus documentation and onboarding time, gain a tremendous benefit by having most of the system being built upon pure functions.

6) Are you able to describe at least two process models and the differences between them? (e.g. multiprocess, single thread).

Node.js event loop

It runs on a single thread, even though under the covers for internal usage it uses different threads, I believe this to be reason why the phrase "everything runs in parallel, except your code" became popular, all i/o is non-blocking, everything else blocks.

One could imagine it as a loop formed by few different steps, each of those handles different types of callbacks:

  • timers - for setTimeout and setInterval
  • i/o - all other callbacks are executed here
  • poll - new i/o events are handled here, this is where Node.js could block for synchronous long running operations

There are also other steps handling more subtle events, but I don't recall them now. What's important to understand is that the event loop runs on a single thread, so for example a server would be blocked waiting for a non i/o task to terminate, before accepting new connections.

Multi thread

I don't think I could go in any detail here, as that's an area that never picked my interest.

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