GOPATH
environment variable..go
extension.go run
command to execute your Go program.
// filepath: /path/to/hello.go
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
function printMessage (obj){
console.log(obj.message.toLowerCase())
// Here is 3 assumptions
// 1) Function will receive object as input
// 2) obj has message property
// 3) message property is type of string
}
printMessage() // TypeError: Cannot read property 'message' of undefined
printMessage('foo') // TypeError: Cannot read property 'toLowerCase' of undefined
printMessage({message: 3}) // TypeError: obj.message.toLowerCase is not a function
printMessage({message: 'Hello World'}) // Happy case. Output hello world
TypeError
in JavaScript is Runtime Error. This means we need to
execute the code to see the
error. Some errors may slip through QA and will affect the end-user experience.
TypeScript is designed to solve this problem by checking static types during
compile time.
TypeScript allows a developer to catch TypeError
at the development
stage before code gets
executed.
We can use the npm
package manager to install TypeScript
npm install -g typescript
To execute the TypeScript compiler use the tsc
command. Example:
tsc test.ts
Let's look at the same
example in TypeScript.
interface MessageObject {
message: string;
}
function printMessage (obj: MessageObject){
console.log(obj.message.toLowerCase())
// Here is 3 assumptions
// 1) Function will receive object as input
// 2) obj has message property
// 3) message property is type of string
}
printMessage() // error TS2554: Expected 1 arguments, but got 0.
// test.ts:5:24 an argument for 'obj' was not provided.
printMessage('foo') // test.ts:15:14 - error TS2345: Argument of type 'string' is not assignable
// to parameter of type 'MessageObject'.
printMessage({message: 3}) // test.ts:16:15 - error TS2322: Type 'number' is not assignable to type 'string'.
printMessage({message: 'Hello World'}) // Happy case. Output hello world
As we can see, error messages are now more descriptive and pointed to the exact line in the code. The main advantage is that we can see errors during compile time right in a development console before code gets executed.
const arr = [ 'foo', 'bar'];
const [first, second] = arr;
console.log(first); // Output: foo
console.log(second); // Output: bar
const arr = [ 'foo', 'bar', 'baz'];
const [first, ,second] = arr; // extra coma
console.log(first); // Output: foo
console.log(second); // Output: baz
// bar skipped
const obj = {x: 'foo', y: 'bar', z: 'baz'};
const {x, y ,z} = obj;
console.log(x); // Output: foo
console.log(y); // Output: bar
console.log(z); // Output: baz
const obj = {x: 'foo', y: 'bar', z: 'baz'};
const {z, y ,x} = obj; // order changed
console.log(x); // Output: foo
console.log(y); // Output: bar
console.log(z); // Output: baz
aliases
.
const obj = {x: 'foo', y: 'bar'};
const {y: yAlias ,x} = obj; // yAlias
console.log(x); // Output: foo
console.log(yAlias); // Output: bar
y = 'garply', z = 'waldo'
const obj = {x: 'foo', y: 'bar'};
const {x, y = 'garply', z = 'waldo'} = obj;
console.log(x); // Output: foo
console.log(y); // Output: bar, value from object
console.log(z); // Output: waldo, default value
...rest
to store remaining properties to rest object.
const obj = {x: 'foo', y: 'bar', z: 'baz'};
const {x, ...others} = obj;
console.log(x); // Output: foo
console.log(others); // Output: { y: 'bar', z: 'baz' }
To support Asynchronous operations. NodeJS implements Event Loop. Event loop is an endless
loop looking for the next task in a JavaScript call stack. If the call stack is empty, the Event loop will
check the Event queue.
The event queue is the place
where callsback functions waiting to be executed.
The Thread pool is the libuv pool of 4 threads that NodeJS can use to
delegate heavy operations like DB connect.
Authentication
service responsible for user registration, login, forget the
password, etc... Authentication
service may not have notification
functionalit implemented.
In case, the HTTP
request to the
Notification
Microservice.
Each Microserviceis responsible for its own security, payload/ model
validation, error handling, and persistent data operations.
Microservice work with dedicated DBs.
For example, access to
USER
data is allowed only through the USER
Microservice. And USER DB
contains only data required for
USER
Microservice operations.
A smaller codebase allows easier reading and understanding of code. Each service can be implemented using an independent technology stack. No programming language or DB dependencies on the application level. Use the programming language and DB of choice that best fits the purpose of the Microservice. |
Microservice can be scaled independently. Scale only Microservices that no longer have the capacity to serve the traffic, it is a more cost-effective scale approach. |
Microservice has fewer dependencies, it helps with the unit and integration testing. |
Microservices allow smaller and faster deployments. Each Microservice is built and deployed as a separate process. No need to rebuild and redeploy the whole application. |
Fault Isolation. If one Microservice fails, the rest of the application quite possibly will continue to operate and services not related to the crashed Microservice continue to be available. |
CI/CD
pipeline is a sequence of programming jobs that implements continuous
integration, delivery, and deployment of the software project. This process is a part of
SDLC
the system/software development life cycle.
syntax (...)
const obj = { foo: 'bar', x: 1 };
const objCopy = {...obj };
// Object { foo: 'bar', x: 1 }
The spread operator
(...)
can be used to merge two objects.
const obj1 = { foo: 'bar', x: 1 };
const obj2 = { waldo: 'baz', y: 2 };
const mergedObj = { ...obj1, ...obj2 };
// Object { foo: 'bar', x: 1, waldo: 'baz', y: 2 }
Read more to see some tricky job interview questions, can you predict the
output?...
const obj1 = { foo: 'bar',
baz: {x:1, y:1}};
const obj2 = { ...obj1 };
obj2.baz.x = 2;
console.log('original:',obj1.baz);
console.log('copy:',obj2.baz);
The output will be
original: { x: 2, y: 1 }
copy: { x: 2, y: 1 }
Spread ...
operator, perform a shallow copy. Properties that hold
primitive values 'foo'
in this example will be copied by value.
obj1
and
obj2
will receive their own copy of the
foo
property. Changing
obj2.foo
will not affect
obj1.foo
. But it works differently for properties of type Object
baz: {x:1, y: 1}
in this example. Objects in JavaScript are copied by
reference. Meaning
obj1.baz
and
obj2.baz
both hold just a reference that points to the same place in memory
where a single copy of
baz
exists.