We present you a free Bootstrap 4 CV template with amazing and responsive design.
Continue reading on Tutorialzine.
Source:: Tutorialzine.com
We present you a free Bootstrap 4 CV template with amazing and responsive design.
Continue reading on Tutorialzine.
Source:: Tutorialzine.com
Ben Nadel reflects on leadership and what we can learn from the final scene of Braveheart and the metamorphosis of Robert the Bruce….
Source:: bennadel.com
Quick tip: npm lets you install directories, which is occasionally useful for organizing projects. For example, as a temporary step before uploading packages to npm (think lightweight npm link
).
Source:: 2ality
Ben Nadel reviews Designing Distributed Systems: Patterns and Paradigms for Scalable, Reliable Services by Brendan Burns. This book is a quick and approachable read that examines container-based design patterns at the container level, node level, and systems level….
Source:: bennadel.com
By Glad Chinda
Some time ago I developed a tutorial showing how to create a password strength meter in an AngularJS application using the zxcvbn JavaScript library by Dropbox. Since React has become the most widely used JavaScript framework in the last few years, I thought it would be helpful to develop a similar tutorial for React applications. If you are interested in the AngularJS article, you can take a look at: Password Strength Meter in AngularJS.
In this tutorial, we will create a simple form with fields for fullname, email and password. We will perform some lightweight form validation and also use the zxcvbn library to estimate the strength of the password in the form while providing visual feedback.
Here is a demo of what we would have created by the end of this tutorial.
Passwords are commonly used for user authentication in most web applications and as such, it is required that passwords be stored in a safe way. Over the years, techniques such as one-way password hashing – which involves salting most of the times, have been employed to hide the real representation of passwords being stored in a database.
Although password hashing is a great step in securing password, the user still poses a major challenge to password security. A user who uses a very common word as password makes the effort of hashing fruitless, since a bruteforce attack can crack such password in a very short time. Infact, if highly sophisticated infrastructure is used for the attack, it may even take split milliseconds, depending on the password complexity or length.
Many web applications today such as Google, Twitter, Dropbox, etc insist on users having considerably strong passwords either by ensuring a minimum password length or some combination of alphanumeric characters and maybe symbols in the password.
How then is password strength measured? Dropbox developed an algorithm for a realistic password strength estimator inspired by password crackers. This algorithm is packaged in a JavaScript library called zxcvbn. In addition, the package contains a dictionary of commonly used English words, names and passwords.
Before we begin, ensure that you have a recent version of Node installed on your system. We will use yarn
to run all our NPM scripts and to install dependencies for our project, so also ensure that you have Yarn installed. You can follow this Yarn installation guide to install yarn
on your system. Also, we will use the popular create-react-app
package to generate our new React application.
Run the following command to install create-react-app
on your system if you haven’t installed it already.
npm install -g create-react-app
Start a new React application using the following command. You can name the application however you desire.
create-react-app react-password-strength
NPM >= 5.2
If you are using
npm
version5.2
or higher, it ships with an additionalnpx
binary. Using thenpx
binary, you don’t need to installcreate-react-app
globally on your system. You can start a new React application with this simple command:npx create-react-app react-password-strength
Next, we will install the dependencies we need for our application. Run the following command to install the required dependencies.
yarn add bootstrap zxcvbn isemail prop-types
yarn add -D npm-run-all node-sass-chokidar
We have installed node-sass-chokidar
as a development dependency for our application to enable us use SASS. For more information about this, see this guide.
Now open the src
directory and change the file extension of all the .css
files to .scss
. The required .css
files will be compiled by node-sass-chokidar
as we continue.
Edit the package.json
file and modify the scripts
section to look like the following:
"scripts": {
"start:js": "react-scripts start",
"build:js": "react-scripts build",
"start": "npm-run-all -p watch:css start:js",
"build": "npm-run-all build:css build:js",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject",
"build:css": "node-sass-chokidar --include-path ./src --include-path ./node_modules src/ -o src/",
"watch:css": "npm run build:css && node-sass-chokidar --include-path ./src --include-path ./node_modules src/ -o src/ --watch --recursive"
}
As you might have noticed, we installed the bootstrap
package as a dependency for our application to get some default styling. To include Bootstrap in the application, edit the src/index.js
file and add the following line before every other import
statement.
import "bootstrap/dist/css/bootstrap.min.css";
yarn start
The application is now started and development can begin. Notice that a browser tab has been opened for you with live reloading functionality to keep in sync with changes in the application as you develop.
At this point, your application view should look like the following screenshot:
Remember we intend to create a simple form with fields for fullname, email and password and also perform some lightweight form validation on the fields. We will create the following React components to keep things as simple as possible.
FormField
– Wraps a form input field with its attributes and change event handler.
EmailField
– Wraps the email FormField
and adds email validation logic to it.
PasswordField
– Wraps the password FormField
and adds the password validation logic to it. Also attaches password strength meter and some other visual cues to the field.
JoinForm
– The fictitious Join Support Team form that houses the form fields.Go ahead and create a components
directory inside the src
directory of the application to house all our components.
FormField
ComponentCreate a new file FormField.js
in the src/components
directory and add the following code snippet to it.
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
class FormField extends Component {
// initialize state
state = { value: '', dirty: false, errors: [] }
hasChanged = e => {
e.preventDefault();
// destructure props - assign default dummy functions to validator and onStateChanged props
const { label, required = false, validator = f => f, onStateChanged = f => f } = this.props;
const value = e.target.value;
const isEmpty = value.length === 0;
const requiredMissing = this.state.dirty && required && isEmpty;
let errors = [];
if (requiredMissing) {
// if required and is empty, add required error to state
errors = [ ...errors, `${label} is required` ];
} else if ('function' === typeof validator) {
try {
validator(value);
} catch (e) {
// if validator throws error, add validation error to state
errors = [ ...errors, e.message ];
}
}
// update state and call the onStateChanged callback fn after the update
// dirty is only changed to true and remains true on and after the first state update
this.setState(({ dirty = false }) => ({ value, errors, dirty: !dirty || dirty }), () => onStateChanged(this.state));
}
render() {
const { value, dirty, errors } = this.state;
const { type, label, fieldId, placeholder, children } = this.props;
const hasErrors = errors.length > 0;
const controlClass = ['form-control', dirty ? hasErrors ? 'is-invalid' : 'is-valid' : '' ].join(' ').trim();
return (
<Fragment>
<div className="form-group px-3 pb-2">
<div className="d-flex flex-row justify-content-between align-items-center">
<label htmlFor={fieldId} className="control-label">{label}</label>
{/** Render the first error if there are any errors **/}
{ hasErrors && <div className="error form-hint font-weight-bold text-right m-0 mb-2">{ errors[0] }</div> }
</div>
{/* Render the children nodes passed to component */}
{children}
<input type={type} className={controlClass} id={fieldId} placeholder={placeholder} value={value} onChange={this.hasChanged} />
</div>
</Fragment>
);
}
}
FormField.propTypes = {
type: PropTypes.oneOf(["text", "password"]).isRequired,
label: PropTypes.string.isRequired,
fieldId: PropTypes.string.isRequired,
placeholder: PropTypes.string.isRequired,
required: PropTypes.bool,
children: PropTypes.node,
validator: PropTypes.func,
onStateChanged: PropTypes.func
};
export default FormField;
We are doing a handful of stuffs in this component. Let’s try to break it down a little bit:
Input State
First, we initialized state for the form field component to keep track of the current value
of the input field, the dirty
status of the field, and any existing validation errors
. A field becomes dirty the moment its value first changes and remains dirty.
Handle Input Change
Next, we added the hasChanged(e)
event handler to update the state value
to the current input value on every change to the input. In the handler, we also resolve the dirty
state of the field. We check if the field is a required
field based on props, and add a validation error to the state errors
array if the value is empty.
However, if the field is not a required field or is required but not empty, then we delegate to the validation function passed in the optional validator
prop, calling it with the current input value, and adding the thrown validation error to the state errors
array (if there is any error).
Finally, we update the state and pass a callback function to be called after the update. The callback function simply calls the function passed in the optional onStateChanged
prop, passing the updated state as its argument. This will become handy for propagating state changes outside the component.
Rendering and Props
Here we are simply rendering the input field and its label. We also conditionally render the first error in the state errors
array (if there are any errors). Notice how we dynamically set the classes for the input field to show validation status using built-in classes from Bootstrap. We also render any children nodes contained in the component.
As seen in the component’s propTypes
, the required props for this component are: type
('text'
or 'password'
), label
, placeholder
and fieldId
. The remaining components are optional.
EmailField
ComponentCreate a new file EmailField.js
in the src/components
directory and add the following code snippet to it.
import React from 'react';
import PropTypes from 'prop-types';
import { validate } from 'isemail';
import FormField from './FormField';
const EmailField = props => {
// prevent passing type and validator props from this component to the rendered form field component
const { type, validator, ...restProps } = props;
// validateEmail function using the validate() method of the isemail package
const validateEmail = value => {
if (!validate(value)) throw new Error('Email is invalid');
};
// pass the validateEmail to the validator prop
return <FormField type="text" validator={validateEmail} {...restProps} />
};
EmailField.propTypes = {
label: PropTypes.string.isRequired,
fieldId: PropTypes.string.isRequired,
placeholder: PropTypes.string.isRequired,
required: PropTypes.bool,
children: PropTypes.node,
onStateChanged: PropTypes.func
};
export default EmailField;
In the EmailField
component, we are simply rendering a FormField
component and passing an email validation function to the validator
prop. We are using the validate()
method of the isemail
package for the email validation.
Also notice that all other props except the type
and validator
props are transferred from the EmailField
component to the FormField
component.
PasswordField
ComponentCreate a new file PasswordField.js
in the src/components
directory and add the following code snippet to it.
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import zxcvbn from 'zxcvbn';
import FormField from './FormField';
class PasswordField extends Component {
constructor(props) {
super(props);
const { minStrength = 3, thresholdLength = 7 } = props;
// set default minStrength to 3 if not a number or not specified
// minStrength must be a a number between 0 - 4
this.minStrength = typeof minStrength === 'number'
? Math.max( Math.min(minStrength, 4), 0 )
: 3;
// set default thresholdLength to 7 if not a number or not specified
// thresholdLength must be a minimum value of 7
this.thresholdLength = typeof thresholdLength === 'number'
? Math.max(thresholdLength, 7)
: 7;
// initialize internal component state
this.state = { password: '', strength: 0 };
}
stateChanged = state => {
// update the internal state using the updated state from the form field
this.setState({
password: state.value,
strength: zxcvbn(state.value).score
}, () => this.props.onStateChanged(state));
};
validatePasswordStrong = value => {
// ensure password is long enough
if (value.length <= this.thresholdLength) throw new Error("Password is short");
// ensure password is strong enough using the zxcvbn library
if (zxcvbn(value).score < this.minStrength) throw new Error("Password is weak");
};
render() {
const { type, validator, onStateChanged, children, ...restProps } = this.props;
const { password, strength } = this.state;
const passwordLength = password.length;
const passwordStrong = strength >= this.minStrength;
const passwordLong = passwordLength > this.thresholdLength;
// dynamically set the password length counter class
const counterClass = ['badge badge-pill', passwordLong ? passwordStrong ? 'badge-success' : 'badge-warning' : 'badge-danger'].join(' ').trim();
// password strength meter is only visible when password is not empty
const strengthClass = ['strength-meter mt-2', passwordLength > 0 ? 'visible' : 'invisible'].join(' ').trim();
return (
<Fragment>
<div className="position-relative">
{/** Pass the validation and stateChanged functions as props to the form field **/}
<FormField type="password" validator={this.validatePasswordStrong} onStateChanged={this.stateChanged} {...restProps}>
<span className="d-block form-hint">To conform with our Strong Password policy, you are required to use a sufficiently strong password. Password must be more than 7 characters.</span>
{children}
{/** Render the password strength meter **/}
<div className={strengthClass}>
<div className="strength-meter-fill" data-strength={strength}></div>
</div>
</FormField>
<div className="position-absolute password-count mx-3">
{/** Render the password length counter indicator **/}
<span className={counterClass}>{ passwordLength ? passwordLong ? `${this.thresholdLength}+` : passwordLength : '' }</span>
</div>
</div>
</Fragment>
);
}
}
PasswordField.propTypes = {
label: PropTypes.string.isRequired,
fieldId: PropTypes.string.isRequired,
placeholder: PropTypes.string.isRequired,
required: PropTypes.bool,
children: PropTypes.node,
onStateChanged: PropTypes.func,
minStrength: PropTypes.number,
thresholdLength: PropTypes.number
};
export default PasswordField;
About
zxcvbn
We finally got to use the
zxcvbn
JavaScript password strength estimator package in this component. The package exports azxcvbn()
function that takes a(password: string)
as its first argument and returns an object with several properties for the password strength estimation. In this tutorial, we would be concerned only with thescore
property, which is an integer from0 - 4
(useful for implementing a strength bar).
0
– too guessable1
– very guessable2
– somewhat guessable3
– safely unguessable4
– very unguessableconsole.log(zxcvbn('password').score); // 0
See the following video on testing the
zxcvbn()
method on the browser’s console.
Here is a breakdown of what is going on in the PasswordField
component.
Initialization
In the constructor()
, we created two instance properties: thresholdLangth
and minStrength
from their corresponding prop passed to the component. The thresholdLength
is the minimum password length before it can be considered considerably long. It defaults to 7
and cannot be lower. The minStrength
is the minimum zxcvbn
score before the password is considered to be strong enough. Its value ranges from 0-4
. It defaults to 3
if not specified appropriately.
We also initialized the internal state of the password field to store the current password
and password strength
.
Handling Password Changes
We defined a password validation function that will be passed to the validator
prop of the underlying FormField
component. The function ensures that the password length is longer than the thresholdLength
and also has a min zxcvbn()
score of the specified minStrength
.
We also defined a stateChanged()
function which will be passed to the onStateChanged
prop of the FormField
component. This function retrieves the updated state of the FormField
component and uses it to compute and update the new internal state of the PasswordField
component.
A callback function to be called after the internal state update. The callback function simply calls the function passed in the optional onStateChanged
prop of the PasswordField
component, passing the updated FormField
state as its argument.
Rendering and Props
Here we simply rendered the underlying FormField
component alongside some elements for input hint, password strength meter and password length counter.
The password strength meter indicates the strength
of the current password
based on the state and is configured to be dynamically invisible
if the password length is 0
. The meter will indicate different colors for different strength levels.
The password length counter indicates when the password is long enough. It shows the password length if the password is not longer than the thresholdLength
, otherwise it shows the thresholdLength
followed by a plus(+)
.
The PasswordField
component accepts two additional optional fields: minStrength
and thresholdLength
as defined in the component’s propTypes
.
JoinForm
ComponentCreate a new file JoinForm.js
in the src/components
directory and add the following code snippet to it.
import React, { Component } from 'react';
import FormField from './FormField';
import EmailField from './EmailField';
import PasswordField from './PasswordField';
class JoinForm extends Component {
// initialize state to hold validity of form fields
state = { fullname: false, email: false, password: false }
// higher-order function that returns a state change watch function
// sets the corresponding state property to true if the form field has no errors
fieldStateChanged = field => state => this.setState({ [field]: state.errors.length === 0 });
// state change watch functions for each field
emailChanged = this.fieldStateChanged('email');
fullnameChanged = this.fieldStateChanged('fullname');
passwordChanged = this.fieldStateChanged('password');
render() {
const { fullname, email, password } = this.state;
const formValidated = fullname && email && password;
// validation function for the fullname
// ensures that fullname contains at least two names separated with a space
const validateFullname = value => {
const regex = /^[a-z]{2,}(s[a-z]{2,})+$/i;
if (!regex.test(value)) throw new Error('Fullname is invalid');
};
return (
<div className="form-container d-table-cell position-relative align-middle">
<form action="/" method="POST" noValidate>
<div className="d-flex flex-row justify-content-between align-items-center px-3 mb-5">
<legend className="form-label mb-0">Support Team</legend>
{/** Show the form button only if all fields are valid **/}
{ formValidated && <button type="button" className="btn btn-primary text-uppercase px-3 py-2">Join</button> }
</div>
<div className="py-5 border-gray border-top border-bottom">
{/** Render the fullname form field passing the name validation fn **/}
<FormField type="text" fieldId="fullname" label="Fullname" placeholder="Enter Fullname" validator={validateFullname} onStateChanged={this.fullnameChanged} required />
{/** Render the email field component **/}
<EmailField fieldId="email" label="Email" placeholder="Enter Email Address" onStateChanged={this.emailChanged} required />
{/** Render the password field component using thresholdLength of 7 and minStrength of 3 **/}
<PasswordField fieldId="password" label="Password" placeholder="Enter Password" onStateChanged={this.passwordChanged} thresholdLength={7} minStrength={3} required />
</div>
</form>
</div>
);
}
}
export default JoinForm;
The JoinForm
component wraps the form field components that make up our form. We initialized state to hold the validity of the three form fields: fullname
, email
and password
. They are all false
initially – that is invalid
.
We also defined state change watch functions for each field to update the form state accordingly. The watch function checks if there are no errors
in a field and updates the form internal state for that field to true
– that is valid
. These watch functions are then assigned to the onStateChanged
prop of each form field component to monitor state changes.
Finally, we rendered the form. Notice that we added a validation function to the fullname
field to ensure that at least two names separated by a space and containing only alphabet chars are provided.
App
ComponentUp till this point, the browser still renders the boilerplate React application. We will go ahead to modify the App.js
file in the src
directory to render the JoinForm
inside the AppComponent
.
The App.js
file should look like the following snippet:
import React from 'react';
import JoinForm from './components/JoinForm';
import './App.css';
const App = () => (
<div className="main-container d-table position-absolute m-auto">
<JoinForm />
</div>
);
export default App;
We are one step away from the final look and feel of our application. At the moment, everything seems to be a little out of place. We will go ahead to define some style rules in the src/App.scss
file to spice up the form.
The App.scss
file should look like the following snippet:
/* Declare some variables */
$primary: #007bff;
// Password strength meter color for the different levels
$strength-colors: (darkred, orangered, orange, yellowgreen, green);
// Gap width between strength meter bars
$strength-gap: 6px;
body {
font-size: 62.5%;
}
.main-container {
width: 400px;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
.form-container {
bottom: 100px;
}
legend.form-label {
font-size: 1.5rem;
color: desaturate(darken($primary, 10%), 60%);
}
.control-label {
font-size: 0.8rem;
font-weight: bold;
color: desaturate(darken($primary, 10%), 80%);
}
.form-control {
font-size: 1rem;
}
.form-hint {
font-size: 0.6rem;
line-height: 1.4;
margin: -5px auto 5px;
color: #999;
&.error {
color: #C00;
font-size: 0.8rem;
}
}
button.btn {
letter-spacing: 1px;
font-size: 0.8rem;
font-weight: 600;
}
.password-count {
bottom: 16px;
right: 10px;
font-size: 1rem;
}
.strength-meter {
position: relative;
height: 3px;
background: #DDD;
margin: 7px 0;
border-radius: 2px;
// Dynamically create the gap effect
&:before,
&:after {
content: '';
height: inherit;
background: transparent;
display: block;
border-color: #FFF;
border-style: solid;
border-width: 0 $strength-gap 0;
position: absolute;
width: calc(20% + #{$strength-gap});
z-index: 10;
}
// Dynamically create the gap effect
&:before {
left: calc(20% - #{($strength-gap / 2)});
}
// Dynamically create the gap effect
&:after {
right: calc(20% - #{($strength-gap / 2)});
}
}
.strength-meter-fill {
background: transparent;
height: inherit;
position: absolute;
width: 0;
border-radius: inherit;
transition: width 0.5s ease-in-out, background 0.25s;
// Dynamically generate strength meter color styles
@for $i from 1 through 5 {
&[data-strength='#{$i - 1}'] {
width: (20% * $i);
background: nth($strength-colors, $i);
}
}
}
We have succeeded in adding the styles required by our application. Notice the use of generated CSS content in the .strength-meter:before
and .strength-meter:after
pseudo-elements to add gaps to the password strength meter.
We also used the Sass @for
directive to dynamically generate fill colors for the strength meter at different password strength levels.
The final app screen should look like this:
With validation errors, the screen should look like this:
And without any errors – that is all fields are valid, the screen should look like this:
In this tutorial, we have been able to create a password strength meter based on the zxcvbn
JavaScript library in our React application. For a detailed usage guide and documentation of the zxcvbn library, see the zxcvbn repository on Github. For a complete code sample of this tutorial, checkout the password-strength-react-demo repository on Github. You can also get a live demo of this tutorial on Code Sandbox.
Source:: scotch.io
By John Papa
We often share slides online. There are several tools that handle this, but none seem to retain all of the intended experience. Why so hard?!
For example, many of them do not retain animations. Even if they do retain some animations, some are almost always lost. This is likely because the tools we create them with don’t handle them in a consistent manner. I use a lot of subtle transitions, animations, and animated gifs in my presentations – and often these are part of the presentation’s experience.
Here is a quick comparison of some of the slide sharing tools.
Notice I did not include some others that allow you to create slides in HTML. The baseline for this comparison is that I want to create my slides in a tool such as keynote, powerpoint or google slides. Those three prove to be the highest quality and easiest tools to design and create slides quickly. While tools like prezi are very cool, I prefer the more powerful tools listed above.
Site | link | Retains Animations | Full Screen | Fonts Retained | Animated GIFs Retained | Custom Links |
Google Slides | https://slides.google.com> | Most | Yes | No | No | Yes |
Slides.com | https://slides.com> | No | Yes | Yes | Yes | No |
Speaker Deck | https://speakerdeck.com> | No | No | Yes | Yes | No |
Slide Share | https://www.slideshare.net> | No | Yes | Yes | Yes | No |
Google Slides are very cool for sharing slides. You create them online and they can do quite a lot. I find them a notch behind PowerPoint and Keynote for some animations and transitions, so I still use Keynote and PowerPoint for creating slides. When I upload slides (powerpoint, keynote, or pdf) from those tools into Google Slides, most of the experience is retained. Often the transitions, some animations, and fonts are lost. It’s worth noting that a custom link can be created using a bit.ly or other link sharing tools. I use a custom domain of jpapa.me for mine.
I also like Slides.com a lot. It allows uploading a powerpoint or pdf file, but all animations are lost. However, unlike Google Slides, the fonts are retained in slides.com.
So which do I use? Depends on whether I feel more strongly that the experience is better with the fonts or the with the animations and animated GIFs.
If I am missing a better experience, feel free to add your constructive comment.
Source:: johnpapa
Below you can find RisingStack‘s collection of the most important Node.js news, updates, projects & tutorials from this week:
Let’s suppose that we have a database which need to be consistently updated with some batch of data, and a Node.JS application which executes queries in database. How to handle these without any bugs?
Watch our keynote to become familiar with the concepts of contract testing and get to know a small library called Pact, that can help integrating contract testing into your current software development workflow.
Let’s take a look at the state of Node.js package managers and what they can do for you! We’ll also try to help you to pick one between npm and yarn!
How to use Node Inspector to debug both JavaScript and TypeScript Node.js applications using Chrome DevTools, Visual Studio Code and WebStorm? Check it out in this post.
Read some tips and tricks to get ready for a JavaScript coding interview and rock your next one!
In this article, we are going to learn how to create a simple API in Node.js and using MS SQL as a data source on which we are going to perform CRUD operation.
We have good news! After receiving a lot of emails asking us to host online trainings, we are happy to announce our two days of ONLINE training, to master Kubernetes.
In the previous Weekly Node.js Update, we collected great articles, like:
& more…
We help you to stay up-to-date with Node.js on a daily basis too. Check out our Node.js news page and its Twitter feed!
Source:: risingstack.com
Ben Nadel explores the Selection API exposed by the browser. And, uses it to draw outlines of the text that is currently selected by the User….
Source:: bennadel.com
By Jake Lumetta
Conventional wisdom counsels starting out with a monolith, but are there exceptions? I asked some top CTOs about their experiences to determine what to consider when making a decision between starting with a monolith versus using microservices straightaway.
My good friend Darby Frey recently kicked off a greenfield project after assuming his new role as Senior Platform Engineering Lead of Gamut. Despite starting out with monolith at his previous company Belly, he discovered that — in the right circumstances — starting with a monolith isn’t always the best way to go.
“As one does, I allowed much of my thinking in my early days [at my new company] to be influenced by my previous company,” Darby told me.
“I was firmly a member of Team Monolith. [I thought] let’s build a single application and just pull things apart later if we start to feel pain.” – Darby Frey
At Belly, Darby and his team broke down their monolith into a fairly large microservices architecture. They managed to get it to a good place, but only after months of trials and tribulations migrating to microservices.
With this experience fresh in his mind, he approached his new project at Gamut a bit more cautious of microservices.
While this was a greenfield project, Darby’s team was small, and he had aggressive timelines, so on the surface, a monolith seemed like the obvious choice.
“[But with this new project], I was anxious to not repeat the mistakes of the past.”
And with that, he found himself faced with a decision we all struggle with, should we start with a monolith or microservices and how do we decide?
The terms monolith and microservices get tossed around a lot, but it’s important to remember that “System architectures lie on a spectrum,” as Zachary Crockett, CTO of Particle told me during an interview.
“When discussing microservices, people tend to focus on one end of that spectrum: many tiny applications passing too many messages to each other. At the other end of the spectrum you have a giant monolith doing too many things. For any real system, there are many possible service oriented architectures between those two extremes.” he explained.
A monolithic application is built as a single, unified unit. Often a monolith consists of three parts:
Another characteristic of a monolith is that it’s often one massive code base. Server side application logic, front end client side logic, background jobs, etc, are all defined in the same code base.
This means if developers want to make any changes or updates, they need to build and deploy the entire stack all at once.
A monolith isn’t a dated architecture that we need to leave in the past. In certain circumstances, a monolith is ideal. I spoke to Steven Czerwinski, Head of Engineering at Scaylr and former Google employee, to better understand this.
“Even though we had had these positive experiences of using microservices at Google, we [at Scaylr] went [for a monolith] route because having one monolithic server means less work for us as two engineers,” he explained. This was back in the early beginnings of Scalyr.
In other words, because his team was small, a unified application was more manageable in comparison to splitting everything up into microservices.
Fewer cross-cutting concerns: a major advantage associated with monolithic architecture is that you only need to worry about cross-cutting concerns, such as logging or caching, for one application.
Less operational overhead: focusing your finances on one application means that there’s only one application that you need to set up logging, monitoring and testing for. A monolith is also generally less complex to deploy since you aren’t organizing multiple deployments.
Easier testing: with a monolith, automated tests are easier to set up and run because everything is under the same roof. With microservices, tests will need to accommodate for different applications on different runtime environments — which can get complex.
Performance: a monolith can also boast performance advantages in comparison to microservices. That’s often because a monolith uses local calls instead of an API call across a network.
Overly-tight coupling: while monoliths can help you avoid entanglement as previously mentioned, a monolith becomes more vulnerable to entanglement the larger it grows. Because everything is so tightly coupled, isolation of services within the monolith becomes arduous, making life difficult when it comes to independent scaling or code maintenance.
Harder to understand: it’s common to find that monoliths are more difficult beasts to understand in comparison to microservices, a problem which rears its head when on-boarding new team members. This is sometimes a direct result of the tight coupling, or perhaps dependencies and side-effects which are not obvious when you’re looking at a particular service or controller.
The developer community has done itself a disservice with the naming of this architecture. The problem is that that there is nothing inherently “micro” about microservices per se. While they tend to be smaller than the average monolith, they do not have to be tiny. Some are, but size is relative and there’s no standard of unit of measure across organizations.
There is no industry consensus of what exactly microservices are. Nevertheless, here’s my take on the definition of microservices:
Microservice architecture refers to the concept of developing a single application as a suite of small services, in contrast to developing them as one, large ‘monolith.’
Each of those broken-up, individualized services run on their own process, communicating with lightweight mechanisms, often an HTTP resource API. Fully-fledged microservices are independently deployable, and yet can work in tandem when necessary.
Better organization: microservice architectures are typically better organized, since each microservice has a very specific job, and is not concerned with the jobs of other components.
Decoupled: decoupled services are also easier to recompose and reconfigure to serve the purposes of different apps (for example, serving both the web clients and public API). They also allow for fast, independent delivery of individual parts within a larger, integrated system.
Performance: under the right circumstances, microservices can have performance advantages depending on how they’re organized because it’s possible to isolate hot services and scale them independent of the rest of the app.
Fewer mistakes: Microservices enable parallel development by establishing a hard-to-cross boundary between different parts of your system. By doing this, you make it hard – or at least harder – to do the wrong thing: namely, connecting parts that shouldn’t be connected, and coupling too tightly those that need to be connected.
Cross-cutting concerns across each service: As you’re building a new microservice architecture, you’re likely to discover lots of cross-cutting concerns that you did not anticipate at design time. You’ll either need to incur the overhead of separate modules for each cross-cutting concern (i.e. testing), or encapsulate cross-cutting concerns in another service layer that all traffic gets routed through. Eventually, even monolithic architectures tend to route traffic through an outer service layer for cross-cutting concerns, but with a monolithic architecture, it’s possible to delay the cost of that work until the project is much more mature.
Higher operational overhead: Microservices are frequently deployed on their own virtual machines or containers, causing a proliferation of VM wrangling work. These tasks are frequently automated with container fleet management tools.
Although it’s important to have a general sense of the pros and cons of monoliths and microservices, knowing those doesn’t necessarily guide decision-making. To help with that, I asked dozens of CTO’s that have made this decision how and why they made the decision they made. Distilled below are several key considerations you should make when deciding for your own organization.
Darby and his team at Gamut were able to delve directly into microservices because he had experience with eCommerce platforms, and his company had a wealth of knowledge concerning the needs and demands of their customers. If he was traveling down an unknown path on the other hand, a monolith may have actually been the safer option.
Often startups are born out of pains experienced at previous companies. In those scenarios sometimes it’s quite clear scaling is going to be a primary requirement, especially in infrastructure based services like cloud log management.
Does your team have experience with microservices? What if you quadruple the size of your team within the next year, are microservices ideal for that situation? Evaluating these dimensions of your team is crucial to the success of your project.
Julien Lemoine, CTO at Algolia, chimed in on this point:
“We have always started with a microservices approach. The main goal was to be able to use different technology to build our service, for two big reasons:
1) We want to use the best tool for each service. Our search API is highly optimized at the lowest level and C++ is the perfect language for that. That said, using C++ for everything is a waste of productivity, especially to build a dashboard!
2) The want the best talents and using only one technology would limit our options. This is why we have different languages in the company.”
If your team is prepared, starting with microservices is wise as it allows you to get used to the rhythm of developing in a microservice environment, right from the start.
In reality, you’re going to need cloud-based infrastructure to make microservices work for your project.
“[Previously], you would want to start with a monolith because you wanted to deploy one database server. The idea of having to set up a database server for every single microservice and then scale out was a mammoth task. Only a huge, tech-savvy organization could do that,” David Strauss, CTO of Pantheon explained to me.
“Whereas today with services like Google Cloud and Amazon AWS, you have many options for deploying tiny things without needing to own the persistence layer for each one.”
“Every time we consider introducing a new service, we have to consider the operational cost of doing so. Each new service adds to the complexity of the infrastructure and makes it a bit harder to reason about service relationships within the system.” — Oleksiy Kovyrin, Head of Swiftype SRE, Elastic
You may think microservices is the “right” way to go as a tech-savvy startup with high ambitions. But microservices pose a business risk. David Strauss explained:
“A lot of teams overbuild their project initially; everyone wants to think their startup will be the next unicorn and that they should, therefore, build everything with microservices or some other hyper-scalable infrastructure. But that’s usually wrong, almost all the time,” he said.
One example of this from his early days at Pantheon was a system that was limited to a single VM. They thought it would be a month or two until they’d be forced to scale it. It ended up being over a year — and they ended up scaling it a completely different way than they had anticipated.
He went on to say that, in these cases, the areas that you thought you needed to scale are probably not the parts that will need to scale first, and that results in misplaced effort even for the systems that will need to scale.
“Know thyself” is a crucial mantra for teams looking to make a decision about microservices versus a monolith. Through trial, error, and success, CTOs described what worked best for them given their specific context, and I’ve distilled this into scenarios that indicate that you should strongly consider one architectural approach over another.
Your team is at founding stage: Your team is small, between 2-5 members, and is thus unable to tackle a broader and high-overhead microservices architecture.
You’re building an unproven product or proof of concept: Are you building an unproven product in the market? If it’s a new idea, it’s likely going to pivot and evolve over time, so a monolith is ideal to allow for rapid product iteration. Same applies to a proof of concept where your goal is just to learn as much as possible as quickly as possible, even if you end up throwing it away.
You have no microservices experience: If your team has no prior experience with microservices, unless you can justify taking the risk of learning “on the fly” at such an early stage, it’s likely another sign you should stick to a monolith to start.
You require quick, independent service delivery: If it’s snappy, isolated service delivery that you need, microservices are your best bet. However, depending on the size of your team, it can take some time before you see any service delivery gains versus starting with monolith.
A piece of your platform needs to be extremely efficient: If your business is doing intensive processing of petabytes of log volume, you’ll likely want to build that service out in a very efficient language (i.e. C++) while your user dashboard may be built in Ruby on Rails.
You plan to scale your team: Starting with microservices gets your team used to developing in separate small teams from the beginning, and having teams separated by service boundaries makes scaling your development organization easier.
Do not attempt to take on microservices just because other engineering teams are having success with them or because microservices seem like a hot topic. Your own context, evaluated against the above considerations, is the key to deciding if you should start with monolith or microservices.
For more content like this, check out our free eBook, Microservices for Startups.
Source:: scotch.io
By Chris Nwamba
If you have ever used online stores like Amazon or eBay, you have definitely used the preview feature. It shows you images or videos of the product so you know what to expect before making a purchase.
In this article, we are going to examine how to build a single page Amazon-like preview app
with Vue.js
What we will build won’t look exactly like the Amazon website, but will exhibit the product preview characteristics.
To build this app, we are going to use a Node server for the back-end and Vue.js for our front-end. Before we get to work, you need to verify that you have a couple of things installed on your machine:
We going to use Vue.js to build the front-end. Vue.js is a progressive JavaScript framework that is quick and easy to use.
Installing Vue.js
You are going to need Vue.js installed on your machine. You can confirm your installation by running:
vue --version
If you get a version number as a result then you have Vue.js installed. If not, it is recommended that you install the Vue CLI by running:
npm install --global vue-cli
To create the frontend
server, run the following :
mkdir preview-app
vue init webpack frontend
This creates a vue example project which we are now going to tweak and adjust.
Installing The Node Modules
We are going to use axios
to make get
requests from one of our Vue.js components so install it by running the following in the frontend
directory:
cd frontend
npm install axios
Creating the Listing Component
This Listing component is responsible for showing all the products we have in the store and adding a link to the view for the product.
To create the Listing
component, we run the following :
touch Listing.vue
In the Listing.vue
, we need to first import the axios
module:
<script>
import axios from 'axios'
//...
And now we use the module to fetch the product listing :
//...
export default {
name: 'Listing',
data () {
return {
products : []
}
},
mounted : function(){
axios.get('http://localhost:3128/products').
then( result => {
console.log( result );
this.products = result.data;
})
}
}
</script>
We can see above that once the component is mounted, we make a call to our back-end server to fetch the available products and then assign it to the product
data of the component.
The template for the component looks like this :
<template>
<div class="listing container">
<div class="title" style="margin-bottom:40px;">
<h1>Products on Sale</h1>
</div>
<div class="row">
<div class="col-sm-2">
<h2>#</h2>
</div>
<div class="col-sm-8">
<h2>PRODUCT NAME</h2>
</div>
<div class="col-sm-2">
<h2>GO TO</h2>
</div>
</div>
<template v-for="product in products">
<div class="row" style="margin-bottom:20px;">
<div class="col-sm-2" >
<p>{{ product.id }}</p>
</div>
<div class="col-sm-8">
<p>{{ product.name }}</p>
</div>
<div class="col-sm-2">
<router-link :to="{path: '/product/'+product.id }">View Product</router-link>
</div>
</div>
</template>
</div>
</template>
In the template above, we list
out the products as divs and add an action button that takes you to the single product page itself.
Creating the Preview Component
The Preview component is responsible for displaying data and images related to the selected product from the previous view. When the component is created, we make a get request to the backend server to fetch all the data for the particular id
and then display the media in the form of a carousel
on the right side of the screen.
Create the Preview.``v``ue
file by running :
touch Preview.vue
In the Vue.js file, we first import the axios
module :
<script>
import axios from 'axios'
//...
Now, we build the component :
//...
export default {
name: 'Preview',
data () {
return {
media :[],
product_name : "",
product_desc : "",
product_price : ""
}
},
mounted : function(){
// now we get all the related infomation for the particular product id
axios.get(`http://localhost:3128/getProductInfo/${this.$route.params.id}`)
.then( res => {
this.media = res.data.media;
this.product_name = res.data.product_name;
this.product_desc = res.data.product_desc;
this.product_price = res.data.product_price;
})
},
methods : {
initializePlayer : function(){
console.log('here')
var cld = cloudinary.Cloudinary.new({ cloud_name: "og-tech", secure: true});
var demoplayer = cld.videoPlayer('video-player');
}
}
</script>
After the post request is made, the model is updated with the data that was returned as a JSON response on the back-end.
Our view has a template that looks as follows :
<template>
<div class="preview">
<div class="row">
<div class="col-sm-6">
<!-- this part will contain the product info -->
<h1> {{ product_name }} </h1>
<div>
<p> {{ product_desc }} </p>
<p> Price : ${{ product_price }} </p>
</div>
</div>
<div class="col-sm-6">
<!-- this part will contain the images -->
<div id="demo" class="carousel slide" data-ride="carousel">
<!-- Indicators -->
<ul class="carousel-indicators">
<template v-for="single_media in media">
<template v-if="single_media.id == 0">
<li data-target="#demo" v-bind:data-slide-to="single_media.id" class="active"></li>
</template>
<template v-else>
<li data-target="#demo" v-bind:data-slide-to="single_media.id"></li>
</template>
</template>
<!-- <li data-target="#demo" data-slide-to="0" class="active"></li>
<li data-target="#demo" data-slide-to="2"></li> -->
</ul>
<!-- The slideshow -->
<div class="carousel-inner">
<template v-for="single_media in media">
<template v-if="single_media.id == 0">
<div class="carousel-item active">
<template v-if="single_media.type == 'image'">
<img class="img-responsive single-image" v-bind:src="single_media.url"/>
</template>
<template v-else>
<video
id="video-player"
controls
class="single-image cld-video-player cld-video-player-skin-dark"
v-bind:data-cld-source="single_media.url"
>
</video>
</template>
</div>
</template>
<template v-else>
<div class="carousel-item">
<template v-if="single_media.type == 'image'">
<img class="img-responsive single-image" v-bind:src="single_media.url"/>
</template>
<template v-else>
<video
id="video-player"
controls
class="single-image cld-video-player cld-video-player-skin-dark"
v-bind:data-cld-source="single_media.url"
>
</video>
</template>
</div>
</template>
</template>
</div>
<!-- Left and right controls -->
<a class="carobbusel-control-prev" href="#demo" data-slide="prev">
<span class="carousel-control-prev-icon"></span>
</a>
<a class="carousel-control-next" href="#demo" data-slide="next" v-on:click="initializePlayer()">
<span class="carousel-control-next-icon"></span>
</a>
</div>
</div>
</div>
</div>
</template>
In the template above, what we want to achieve is to display the media for the particular product. If you take a look at when we built the component, we make a request to the backend and then send the response to the Vue component.
We need to know if the media being displayed is an image or a video. So we check in the template;
//..
<template v-if="single_media.type == 'image'">
<img class="img-responsive single-image" v-bind:src="single_media.url"/>
</template>
<template v-else>
<video
id="video-player"
controls
class="single-image cld-video-player cld-video-player-skin-dark"
v-bind:data-cld-source="single_media.url"
>
</video>
</template>
//..
If it has type
of image
, we display the image in the carousel but if type
is a video, we use the Cloudinary VIdeo Player to display the video. To initialize the video player, we add v-on:click
event to the >
button.
Once the button is clicked, the video player is initialized with the video.
PS: Cloudinary’s video player also playing videos by tags and playing playlists. You can read more about it here.
The preview view has some scoped styling as follows :
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
.carousel-inner{
height : 500px;
}
.carousel-item{
height : 100%;
}
.single-image{
width : 100%;
height: 100%;
object-fit : fill;
}
#demo{
margin-left: 30px;
margin-right: 30px;
}
</style>
To build our back-end, we need to change directory to the root directory of our application and then install the node modules:
cd preview-app
npm install cors express body-parser dotenv request connect-multiparty cloudinary
Once this is done, you have successfully installed all the modules necessary for you to build the project.
Create a server.js file
Now we need to create a file that will contain the instructions for our server to work
In your video-suggestion
directory,
touch server.js
This will be the start-up file that will be referenced when your server is running
In your server.js file, you need to
Import the node modules
require('dotenv').config()
const cors = require('cors')
const express = require('express')
const bodyParser = require('body-parser')
const multipart = require('connect-multiparty')
const request = require('request')
const cloudinary = require('cloudinary')
//...
Once you have imported your node modules, you can then use them freely all through your script.
Create your express app
Now we create our express app instance by adding the following to the server.js
//...
const app = express()
//...
Load the middlewares
We load the middlewares in our server.js
by adding the following
//...
app.use(cors())
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
const multipartMiddleware = multipart();
//...
Here, we set our app to use cors
. We also instructed the app the parse the requests in JSON format.
Configure the Cloudinary Client
We need to configure our cloudinary client using your CLOUD_NAME
, API_KEY
and API_SECRET
//...
cloudinary.config({
cloud_name: 'CLOUDINARY_CLOUD_NAME',
api_key: 'CLOUDINARY_API_KEY',
api_secret: 'CLOUDINARY_API_SECRET'
});
//...
Once this is done, then we have successfully configured our Cloudinary client.
Create app routes
Our back-end server is very simple, it’s an express web server with two major routes:
/products
– Lists all the products available for sale./getProductInfo
– Returns data for the selected product. //...
app.get('/products', multipartMiddleware, function(req, res){
return res.json([
{id: '1', name: 'UltraLight Mechanical Keyboard'},
{id: '121', name: 'IPhone X'},
{id: '23', name: 'Tesla S'},
{id: '42', name: 'Work Shoes'}
]);
});
app.get('/getProductInfo/:id', multipartMiddleware, function(req, res){
console.log( req.params.id );
return res.json({
media: [
{
id: '0',
type: 'image',
url: 'https://static.pexels.com/photos/265631/pexels-photo-265631.jpeg'
},
[...]
{
id: '3',
type: 'video',
url:
'http://res.cloudinary.com/og-tech/video/upload/s--ZWPqo282--/v1514966645/sea_turtle-short_z1pr4o.mp4'
},
],
product_name: 'Ultra Thin Mechanical Keyboard',
product_desc: 'This keyboard gives you the clack to your click',
product_price: '200'
})
});
//...
In the above, we see the routes returning responses in JSON format for it to be further used at the frontend. You may have observed that a lot (all) the data returned to the user was static. In a real-world application, you would return dynamic data to the user.
The /productInfo
route accepts the id
of your product so that is what you would use to identify what data to serve instead of just returning static json data. In other words, you can make further query to your database or cloud storage to fetch the information and return the data in the format used above.
Configure Application Port
Now we set the port we want the app to listen on:
[...]
let port = 3128 || process.env.PORT;
app.listen(port, function () {
console.log('App listening on port ' + port + '!');
});
In this article we have see how to leverage Cloudinary’s image and video capabilities using Vue.js to build an Amazon-like preview app for products.
You also can head over here if you want to find out more about optimizing images served on your website f and more about improving your store’s SEO by engineering better Google mobile search ranking through image optimization.
Now you can use concepts shared here in building your own application for the #NextBillionUsers
Here a link to the GitHub repository for more references.
Source:: scotch.io