<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Etinosa Obaseki</title>
    <description>The latest articles on DEV Community by Etinosa Obaseki (@obasekietinosa).</description>
    <link>https://dev.to/obasekietinosa</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F357590%2F8f2abe32-cfd9-4363-b7e3-73bf94b4380f.jpeg</url>
      <title>DEV Community: Etinosa Obaseki</title>
      <link>https://dev.to/obasekietinosa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/obasekietinosa"/>
    <language>en</language>
    <item>
      <title>The Opportunity Cost of Non-functional Requirements</title>
      <dc:creator>Etinosa Obaseki</dc:creator>
      <pubDate>Thu, 11 Jun 2020 07:37:00 +0000</pubDate>
      <link>https://dev.to/obasekietinosa/the-opportunity-cost-of-non-functional-requirements-419b</link>
      <guid>https://dev.to/obasekietinosa/the-opportunity-cost-of-non-functional-requirements-419b</guid>
      <description>&lt;h2&gt;Requirements Engineering&lt;/h2&gt;

&lt;p&gt;In Software Engineering, requirements are descriptions of what the system should do and how it should behave. Requirements also specify the constraints the system will operate under.&lt;/p&gt;

&lt;p&gt;The process of Requirements Engineering is extremely important and often sets the tone for the rest of the &lt;strong&gt;Software Development Lifecycle&lt;/strong&gt; regardless of the development model (Waterfall, Agile, etc.) in use.&lt;/p&gt;

&lt;p&gt;Requirements are divided into:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Functional Requirements which are concerned with &lt;em&gt;what&lt;/em&gt; the system should &lt;em&gt;do&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Non-functional Requirements are concerned with &lt;em&gt;how&lt;/em&gt; the system should &lt;em&gt;be&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Non-functional Requirements (also called quality attributes) are the major concern of Software Architecture. &lt;/p&gt;

&lt;h2&gt;Opportunity Cost of Quality Attributes&lt;/h2&gt;

&lt;p&gt;Most quality attributes in building information systems have a triangular relationship where as you lean towards any two, you forgo more of the third.&lt;/p&gt;

&lt;p&gt;Consider an example with regards to cybersecurity and performance in in these systems. You can have: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Security &lt;/li&gt;
&lt;li&gt;Performance &lt;/li&gt;
&lt;li&gt;Usability&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Caching will improve performance and usability, but will introduce vectors for attack thus, compromising security.&lt;/p&gt;

&lt;p&gt;Of course, there are patterns and techniques that invalidate cycles like these, but it helps to be aware of them.&lt;/p&gt;

&lt;p&gt;You can have Personalization, apps, recommendations tailored to your taste and Portability, these preferences migrate with you as you move from one medium or device to another but Privacy will need to take a hit.&lt;/p&gt;

&lt;p&gt;As we've said, there are ways to escape the cycle depending on how much we're willing to re-architecture.&lt;/p&gt;

&lt;p&gt;For example, with these 3 P's, if the user had their own, self hosted service for managing Preferences and they could take that with them to other Platforms, then that would take care of the Privacy concern, since no third party would need to be involved.&lt;/p&gt;

&lt;h2&gt;References and Further Reading&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Wikipedia: Non-functional requirement &lt;a href="https://en.wikipedia.org/wiki/Non-functional_requirement"&gt;https://en.wikipedia.org/wiki/Non-functional_requirement&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Software Engineering 9th Edition by Ian Sommerville: &lt;a href="https://www.pearson.com/us/higher-education/product/Sommerville-Software-Engineering-9th-Edition/9780137035151.html"&gt;https://www.pearson.com/us/higher-education/product/Sommerville-Software-Engineering-9th-Edition/9780137035151.html&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;



</description>
    </item>
    <item>
      <title>Deep Dive into The Laravel Artisan file</title>
      <dc:creator>Etinosa Obaseki</dc:creator>
      <pubDate>Wed, 03 Jun 2020 19:33:26 +0000</pubDate>
      <link>https://dev.to/obasekietinosa/deep-dive-into-the-laravel-artisan-file-3nge</link>
      <guid>https://dev.to/obasekietinosa/deep-dive-into-the-laravel-artisan-file-3nge</guid>
      <description>&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;The popular PHP framework, Laravel comes with a CLI tool, &lt;code&gt;artisan&lt;/code&gt; that offers a lot of the functionality that makes the framework so useful.&lt;/p&gt;

&lt;p&gt;From preinstalled system commands like &lt;code&gt;$ php artisan migrate&lt;/code&gt; to any custom commands you write, you've used artisan.&lt;/p&gt;

&lt;p&gt;In this article, we'll explore every line of the artisan file and figure out what they do and how it's all tied together.&lt;/p&gt;

&lt;h2&gt;The artisan File&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;#!/usr/bin/env php
&amp;lt;?php
 
define('LARAVEL_START', microtime(true));
 
/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader
| for our application. We just need to utilize it! We'll require it
| into the script here so that we do not have to worry about the
| loading of any our classes "manually". Feels great to relax.
|
*/
 
require __DIR__.'/vendor/autoload.php';
 
$app = require_once __DIR__.'/bootstrap/app.php';
 
/*
|--------------------------------------------------------------------------
| Run The Artisan Application
|--------------------------------------------------------------------------
|
| When we run the console application, the current CLI command will be
| executed in this console and the response sent back to a terminal
| or another output device for the developers. Here goes nothing!
|
*/
 
$kernel = $app-&amp;gt;make(Illuminate\Contracts\Console\Kernel::class);
 
$status = $kernel-&amp;gt;handle(
    $input = new Symfony\Component\Console\Input\ArgvInput,
    new Symfony\Component\Console\Output\ConsoleOutput
);
 
/*
|--------------------------------------------------------------------------
| Shutdown The Application
|--------------------------------------------------------------------------
|
| Once Artisan has finished running, we will fire off the shutdown events
| so that any final work may be done by the application before we shut
| down the process. This is the last thing to happen to the request.
|
*/
 
$kernel-&amp;gt;terminate($input, $status);
 
exit($status);&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Line by Line Analysis&lt;/h2&gt;

&lt;h4&gt;Line 1&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;#!/usr/bin/env php&lt;/code&gt; &lt;/pre&gt;

&lt;p&gt;This line is something called a shebang. A shebang tells the command line where to look for the interpreter for a particular script. &lt;/p&gt;

&lt;p&gt;For example, when writing bash scripts it is common to see a shebang such as &lt;code&gt;#!/bin/bash&lt;/code&gt; at the top which points to the bash shell that will execute the script. &lt;/p&gt;

&lt;p&gt;The shebang in this bash example uses an absolute path to the bash executable while the one from the artisan file uses a logical path. &lt;a rel="noreferrer noopener" href="https://unix.stackexchange.com/questions/29608/why-is-it-better-to-use-usr-bin-env-name-instead-of-path-to-name-as-my"&gt;This UNIX Stack Exchange Question&lt;/a&gt; features some interesting views on the subject.&lt;/p&gt;

&lt;p&gt;It only works on UNIX-like systems, so Mac OS X or Linux but not Windows (although, if you use &lt;strong&gt;git bash&lt;/strong&gt; it should work).&lt;/p&gt;

&lt;p&gt;In the artisan case, our shebang uses the &lt;code&gt;env&lt;/code&gt; command to find the first php executable in the user's path, wherever it may be.&lt;/p&gt;

&lt;p&gt;Shebangs mostly allow you run scripts in the command line without first calling the interpreter. For example, running artisan commands without prepending &lt;strong&gt;php&lt;/strong&gt; to it.&lt;/p&gt;

&lt;p&gt;You can set this up by first making the artisan script executable via &lt;code&gt;chmod +x artisan&lt;/code&gt; and then running &lt;code&gt;./artisan &amp;lt;your-command&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Take note of the dot in front of the artisan. That tells the shell that you want to run that as a command.&lt;/p&gt;

&lt;p&gt;The next line is just a regular opening php tag, so we'll skip ahead to line 4.&lt;/p&gt;

&lt;h4&gt;Line 4&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;define('LARAVEL_START', microtime(true));&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This line creates a PHP constant  &lt;code&gt;&lt;strong&gt;LARAVEL_START&lt;/strong&gt;&lt;/code&gt; and assigns it the value of &lt;code&gt;&lt;strong&gt;microtime(true)&lt;/strong&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;According to the PHP Documentation, "&lt;strong&gt;&lt;code&gt;microtime()&lt;/code&gt;&lt;/strong&gt; returns the current Unix timestamp with microseconds.". It returns a string value by default, but passing the optional &lt;code&gt;$get_as_float&lt;/code&gt; parameter as &lt;code&gt;true&lt;/code&gt; returns a float instead.  &lt;/p&gt;

&lt;p&gt;So, where does this get used in the framework and what is it for? Well, I ran a quick search on the &lt;a rel="noreferrer noopener" href="https://github.com/laravel/framework"&gt;laravel/framework repo&lt;/a&gt; and didn't find any references to the constant. &lt;/p&gt;

&lt;p&gt;My best guess, is that it's used to test how fast the framework starts up or serves request. You can compare the &lt;code&gt;LARAVEL_START&lt;/code&gt; value to the value of &lt;code&gt;microtime(true)&lt;/code&gt; when your request is completed.&lt;/p&gt;

&lt;p&gt;I found &lt;a rel="noreferrer noopener" href="https://stackoverflow.com/questions/52882802/what-and-where-comes-the-actual-usage-of-laravel-start-const-defined-in-index-ph"&gt;this Stack Overflow question and answer&lt;/a&gt; that seems to support my guess. Although, it's asking about the variable in &lt;strong&gt;index.php&lt;/strong&gt; (the application entrypoint for web requests just as artisan is the entrypoint for console "requests").&lt;/p&gt;

&lt;p&gt;The next few lines we'll look at feature the first docblock in the artisan file.&lt;/p&gt;

&lt;h4&gt;Lines 6 - 16&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;/*

|--------------------------------------------------------------------------

| Register The Auto Loader

|--------------------------------------------------------------------------

|

| Composer provides a convenient, automatically generated class loader

| for our application. We just need to utilize it! We'll require it

| into the script here so that we do not have to worry about the

| loading of any our classes "manually". Feels great to relax.

|

*/&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here we have a docblock describing the composer-provided autoloader and why Laravel uses it.&lt;/p&gt;

&lt;p&gt;A fun fact about Taylor Otwell and Laravel's docblock is that (for multiline comments) each line is exactly 3 characters less than the preceding. Go ahead and check for yourself here!&lt;/p&gt;

&lt;p&gt;And, interestingly, &lt;a rel="noreferrer noopener" href="https://twitter.com/maker_schmitz/status/563929347594420224?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E563929477265121280&amp;amp;ref_url=https%3A%2F%2Fservices.etin.space%2Fnotes%2Fwp-admin%2Fpost.php%3Fpost%3D437%26action%3Dedit"&gt;according to this tweet&lt;/a&gt;, he did them by hand.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/taylorotwell/status/563929477265121280"&gt;https://twitter.com/taylorotwell/status/563929477265121280&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next line we'll consider focuses on including the autoloader.&lt;/p&gt;

&lt;h4&gt;Line 18&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;require __DIR__.'/vendor/autoload.php';&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This &lt;strong&gt;require&lt;/strong&gt; directive loads in the autoload.php file that is included in the vendor directory after successfully running &lt;code&gt;$ composer install&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To learn more about how Composer works especially in the context of Laravel I would recommend &lt;a rel="noreferrer noopener" href="https://alanstorm.com/composer_autoloader_part_1/"&gt;this excellent article by Alan Storm on the subject&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next, we'll turn our attention to Line 20 &lt;/p&gt;

&lt;h4&gt;Line 20&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;$app = require_once __DIR__.'/bootstrap/app.php';&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This line creates and initializes the &lt;code&gt;$app&lt;/code&gt; variable with the contents of &lt;strong&gt;/bootstrap/app.php&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;app.php&lt;/strong&gt; initializes a new instance of the Laravel application which is basically the &lt;strong&gt;IoC container&lt;/strong&gt; and returns that value from the script.&lt;/p&gt;

&lt;p&gt;Thus, the &lt;code&gt;$app&lt;/code&gt; variable contains an instance of our Laravel application and we can basically load and use any parts of the application we want. &lt;/p&gt;

&lt;p&gt;For example, using the &lt;code&gt;make()&lt;/code&gt; method to resolve a class' dependencies and create an instance of it.&lt;/p&gt;

&lt;p&gt;This is exactly the same as what we can do with the &lt;code&gt;app()&lt;/code&gt; helper method that we use within our code.&lt;/p&gt;

&lt;p&gt;Next, more comment shenanigans!&lt;/p&gt;

&lt;h4&gt;Lines 22 - 31&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;/*

|--------------------------------------------------------------------------

| Run The Artisan Application

|--------------------------------------------------------------------------

|

| When we run the console application, the current CLI command will be

| executed in this console and the response sent back to a terminal

| or another output device for the developers. Here goes nothing!

|

*/&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here we have another docblock. Once again, with each line 3 characters less than the preceding. &lt;/p&gt;

&lt;p&gt;Doing something like this, especially if it's by hand, would have to be difficult.&lt;/p&gt;

&lt;p&gt;I remember watching an episode on &lt;a rel="noreferrer noopener" href="https://Laracasts.com"&gt;Laracasts&lt;/a&gt; where Jeffrey Way says it's just another example of how much care and detail Taylor Orwell puts into the framework. I'm inclined to agree.&lt;/p&gt;

&lt;p&gt;This block talks about the app lifecycle from the console command to output along with a cheeky &lt;em&gt;"here goes nothing!"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Next we'll use the &lt;code&gt;$app&lt;/code&gt; variable from above on Line 33.&lt;/p&gt;

&lt;h4&gt;Line 33&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;$kernel = $app-&amp;gt;make(Illuminate\Contracts\Console\Kernel::class);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So, here we initialize another variable, &lt;code&gt;$kernel&lt;/code&gt;, using the app container to resolve &lt;code&gt;Kernel&lt;/code&gt; class via the &lt;code&gt;make()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Of course, it's not a concrete class we are passing into the &lt;code&gt;make()&lt;/code&gt; method but an interface. This is a great example of &lt;a href="https://notes.etin.space/posts/solid-in-laravel-too-much-or-not-enough" rel="noreferrer noopener"&gt;the SOLID principles at work in Laravel&lt;/a&gt;, particularly the &lt;strong&gt;Liskov Substitution Principle&lt;/strong&gt; and &lt;strong&gt;Dependency Inversion&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It allows us to easily switch out the concrete kernel class that is called if we need to by simply changing the binding of the interface to the concrete class.&lt;/p&gt;

&lt;p&gt;Typically, within our own application code, we will register such bindings within a service provider class as &lt;a rel="noreferrer noopener" href="https://laravel.com/docs/7.x/container#binding-basics"&gt;recommended by the Laravel Documentation on the matter&lt;/a&gt;, but in the &lt;strong&gt;artisan&lt;/strong&gt; file, such a binding would happen too late.&lt;/p&gt;

&lt;p&gt;So, instead the binding is done within the &lt;strong&gt;/bootstrap/app.php&lt;/strong&gt;. This file binds the different Kernels for console (which is used by artisan) and web as well as the Exception Handler.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$app-&amp;gt;singleton(

    Illuminate\Contracts\Http\Kernel::class,

    App\Http\Kernel::class

);

 

$app-&amp;gt;singleton(

    Illuminate\Contracts\Console\Kernel::class,

    App\Console\Kernel::class

);

 

$app-&amp;gt;singleton(

    Illuminate\Contracts\Debug\ExceptionHandler::class,

    App\Exceptions\Handler::class

);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As we see from the above, the &lt;strong&gt;Kernel&lt;/strong&gt; contract resolves to &lt;strong&gt;App\Console\Kernel&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;With the instance of Kernel loaded into the variable, we are now set to run the actual artisan command. &lt;/p&gt;

&lt;p&gt;The next few lines we'll consider handle this.&lt;/p&gt;

&lt;h4&gt;Lines 35-38&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;$status = $kernel-&amp;gt;handle(

    $input = new Symfony\Component\Console\Input\ArgvInput,

    new Symfony\Component\Console\Output\ConsoleOutput

);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here we assign the output of the &lt;code&gt;$kernel-&amp;gt;handle()&lt;/code&gt; method into the &lt;code&gt;$status&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;If we visit the &lt;strong&gt;App\Console\Kernel&lt;/strong&gt; class, we'll find that it inherits from &lt;strong&gt;&lt;a rel="noreferrer noopener" href="https://github.com/laravel/framework/blob/7.x/src/Illuminate/Foundation/Console/Kernel.php"&gt;Illuminate\Foundation\Console\Kernel&lt;/a&gt;&lt;/strong&gt; which is where the &lt;code&gt;handle()&lt;/code&gt; method resides.&lt;/p&gt;

&lt;p&gt;The method takes two arguments - &lt;code&gt;$input&lt;/code&gt; and &lt;code&gt;$output&lt;/code&gt; - runs some bootstrapping to load the providers and other required services before creating an instance of the &lt;a rel="noreferrer noopener" href="https://github.com/laravel/framework/blob/7.x/src/Illuminate/Console/Application.php"&gt;artisan application&lt;/a&gt; and calling it's &lt;code&gt;run($input, $output)&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;The method returns the status code of the action and it is this value that eventually gets passed into our &lt;code&gt;$status&lt;/code&gt; variable in the &lt;strong&gt;artisan&lt;/strong&gt; file.&lt;/p&gt;

&lt;p&gt;The input and output variables we passed to the &lt;code&gt;run()&lt;/code&gt; method must be instances of &lt;strong&gt;Symfony\Component\Console\Input\InputInterface&lt;/strong&gt; &amp;amp; &lt;strong&gt;Symfony\Component\Console\Output\OutputInterface&lt;/strong&gt; respectively. This is another example of the two SOLID principles we mentioned earlier. Being able to easily switch out the concrete implementations makes it easier for us to use a different input and output for testing purposes or if our application needs are different.&lt;/p&gt;

&lt;p&gt;Up next, we encounter another docblock. &lt;/p&gt;

&lt;h4&gt;Lines 40 - 49&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;/*

|--------------------------------------------------------------------------

| Shutdown The Application

|--------------------------------------------------------------------------

|

| Once Artisan has finished running, we will fire off the shutdown events

| so that any final work may be done by the application before we shut

| down the process. This is the last thing to happen to the request.

|

*/&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You know the drill by know. Another docblock that leaves me wondering how much time must have gone into phrasing the sentences.&lt;/p&gt;

&lt;p&gt;This one talks about the shutdown process for the command.&lt;/p&gt;

&lt;h4&gt;Line 51&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;$kernel-&amp;gt;terminate($input, $status);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To begin the shutdown process, we make a call to the &lt;code&gt;terminate()&lt;/code&gt; method on the $kernel instance. Once again, this method is defined on &lt;strong&gt;&lt;a rel="noreferrer noopener" href="https://github.com/laravel/framework/blob/7.x/src/Illuminate/Foundation/Console/Kernel.php"&gt;Illuminate\Foundation\Console\Kernel&lt;/a&gt;&lt;/strong&gt; and simply calls the terminate() method on the &lt;strong&gt;app&lt;/strong&gt; instance. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;terminate()&lt;/code&gt; method takes in two arguments but appears to do nothing with them.&lt;/p&gt;

&lt;p&gt;And now, the final line.&lt;/p&gt;

&lt;h4&gt;Line 53&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;exit($status);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;According to the PHP Docs, this method terminates the execution of a script. It goes on to say the following about the optional $status argument:&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;status&lt;/code&gt; is a string, this function prints the &lt;code&gt;status&lt;/code&gt; just before exiting.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"If &lt;code&gt;status&lt;/code&gt; is an &lt;a href="https://www.php.net/manual/en/language.types.integer.php"&gt;integer&lt;/a&gt;, that value will be used as the exit status and not printed. Exit statuses should be in the range 0 to 254, the exit status 255 is reserved by PHP and shall not be used. The status 0 is used to terminate the program successfully."&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;In exploring the artisan file, I have regained an appreciation for Laravel's architecture. &lt;/p&gt;

&lt;p&gt;The entrypoint for web requests (index.php) will feature many of the same structures and ideas.&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
    </item>
    <item>
      <title>Gitpodifying a new Laravel Application</title>
      <dc:creator>Etinosa Obaseki</dc:creator>
      <pubDate>Tue, 26 May 2020 16:41:39 +0000</pubDate>
      <link>https://dev.to/obasekietinosa/gitpodifying-a-new-laravel-application-57pp</link>
      <guid>https://dev.to/obasekietinosa/gitpodifying-a-new-laravel-application-57pp</guid>
      <description>&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;&lt;a rel="noreferrer noopener" href="https://GitPod.io"&gt;Gitpod&lt;/a&gt; is a SaaS platform that offers Ready-To-Code dev environments. What this means is that GitPod allows you describe your Development Environment as code and easily provision or share it.&lt;/p&gt;

&lt;p&gt;This is great for letting people quickly try out a new library or framework and even for day to day development.&lt;/p&gt;

&lt;p&gt;&lt;a rel="noreferrer noopener" href="https://www.gitpod.io/blog/gitpodify/"&gt;This article from the GitPod blog&lt;/a&gt; is a great explanation for the problem GitPod solves as well as a fantastic general purpose guide.&lt;/p&gt;

&lt;p&gt;Here, we'll extend on that specifically for the Laravel framework and see how to create a Ready-To-Code environment for our projects.&lt;/p&gt;

&lt;h2&gt;Getting Started&lt;/h2&gt;

&lt;p&gt;The first step is to navigate to the GitHub repository you'd like to set up.&lt;/p&gt;

&lt;p&gt;For this example, I'll use a Laravel project we're building at WTXtra.&lt;/p&gt;

&lt;p&gt;The GitHub repository is publicly available at &lt;a href="https://github.com/WeTalkSound/trivyeah-core/"&gt;https://github.com/WeTalkSound/trivyeah-core/&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Next, we'll just edit this URL slightly to launch a Gitpod workspace for this repo.&lt;/p&gt;

&lt;p&gt;We'll add &lt;strong&gt;"gitpod.io/#"&lt;/strong&gt; in front of the repo URL and hit enter. For the example above, that'll be &lt;a href="https://gitpod.io/#https://github.com/WeTalkSound/trivyeah-core/"&gt;https://gitpod.io/#https://github.com/WeTalkSound/trivyeah-core/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For first time Gitpod users, you'll be asked to sign in with GitHub and authorize the application.&lt;/p&gt;

&lt;p&gt;When we go to this URL, Gitpod begins building our workspace and you'll see the splash screen.&lt;/p&gt;

&lt;p&gt;To determine how to set up the environment, Gitpod follows the instructions in a &lt;strong&gt;.gitpod.yml&lt;/strong&gt; file. If this file does not exist, then it approximates an environment based on your repo.&lt;/p&gt;

&lt;h2&gt;Set up .gitpod.yml&lt;/h2&gt;

&lt;p&gt;The gitpod.yml file specifies the commands that the environment should run on build as well as the Dockerfile to use to build the container. Adding a custom Dockerfile is optional, but potentially offers us more control over the environment we end up with.&lt;/p&gt;

&lt;p&gt;So, we'll create a simple .gitpod.yml file with the following:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;image:
  file: .gitpod.Dockerfile&lt;/code&gt;
&lt;/pre&gt;

&lt;p&gt;And right next to it, create a &lt;strong&gt;.gitpod.Dockerfile&lt;/strong&gt; like so:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;FROM gitpod/workspace-mysql               

USER gitpod&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This uses the gitpod/workspace-mysql as the base image. This image installs and configures MySQL with a root user with no password.&lt;/p&gt;

&lt;p&gt;This works to get you an environment with (almost) everything you need, but there is still some basic housekeeping most Laravel apps will need to take care of.&lt;/p&gt;

&lt;h3&gt;Setting up a Database&lt;/h3&gt;

&lt;p&gt;On the first run of our environment, we'll need to create the database our app will use.&lt;/p&gt;

&lt;p&gt;If you're familiar with docker, you can easily do this from within your custom Dockerfile. However, I prefer to do it from the .gitpod.yml file.&lt;/p&gt;

&lt;p&gt;Within the Gitpod configuration file, we can specify any number of tasks to be run. We can specify tasks to be run only the first time a container is being provisioned or we can specify that it be run even time the container starts.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;image:
  file: .gitpod.Dockerfile
&lt;strong&gt;tasks:
  - init: mysql -u root -e "create database trivyeah"&lt;/strong&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We'll modify our .gitpod.yml file and add the tasks section to it. It specifies that on init, we'll run the command &lt;code&gt;mysql -u root -e "create database trivyeah"&lt;/code&gt; which will log into MySQL as root (with no password) and execute the command specified by the &lt;code&gt;e&lt;/code&gt; flag, in this case, creating a database called &lt;strong&gt;trivyeah&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;Creating a .env file&lt;/h3&gt;

&lt;p&gt;We'll use the .&lt;strong&gt;env.example&lt;/strong&gt; file provided by default with new Laravel installations. In here, we'll specify all the keys that need to be used by the application, including the database name we created above.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;...
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
&lt;strong&gt;DB_DATABASE=trivyeah&lt;/strong&gt;
DB_USERNAME=root
DB_PASSWORD=
...&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Any other default information we'll need to provision our app can be added to the env.example file.&lt;/p&gt;

&lt;p&gt;Next, we will copy the .env.example file to the .env file&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;image:
  file: .gitpod.Dockerfile
tasks:
  - init: mysql -u root -e "create database trivyeah" &lt;strong&gt;&amp;amp;&amp;amp; cp .env.example .env&lt;/strong&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We'll add this to the init command, since we only want it to copy for the first run of the container.&lt;/p&gt;

&lt;h3&gt;Installing Dependencies&lt;/h3&gt;

&lt;p&gt;This is another action we will need to perform on initialization of the environment. We'll run the composer and npm (or yarn, if you prefer) commands in the init action as well.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;image:
  file: .gitpod.Dockerfile
tasks:
  - init: mysql -u root -e "create database trivyeah" &amp;amp;&amp;amp; cp .env.example .env &amp;amp;&amp;amp; &lt;strong&gt;composer install &amp;amp;&amp;amp; npm install&lt;/strong&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;At this point, we can begin using &lt;code&gt;artisan&lt;/code&gt; commands for any other application specific setup we need to.&lt;/p&gt;

&lt;p&gt;For example, we'll need to generate a unique application key for our .env&lt;/p&gt;

&lt;h3&gt;Generate Application Key&lt;/h3&gt;

&lt;p&gt;In a new Laravel application, we'll need to run the &lt;code&gt;php artisan key:generate&lt;/code&gt; command to fill the APP_KEY field in the .env file.&lt;/p&gt;

&lt;p&gt;However, it's a command we'll only need to run the first time. So, we'll add it to the init field of our configuration again.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;image:
  file: .gitpod.Dockerfile
tasks:
  - init: mysql -u root -e "create database trivyeah" &amp;amp;&amp;amp; cp .env.example .env &amp;amp;&amp;amp; composer install &amp;amp;&amp;amp; npm install &amp;amp;&amp;amp; &lt;strong&gt;php artisan key:generate&lt;/strong&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;At this point, all the set up should be done. If you have any other setup specific to your Laravel app, they can be added here as well. &lt;/p&gt;

&lt;p&gt;The init entry is getting unwieldy and so we'll refactor it as soon as we're done with everything else. &lt;/p&gt;

&lt;p&gt;The next thing to do is run migrations before we serve the app.&lt;/p&gt;

&lt;h3&gt;Run Migrations&lt;/h3&gt;

&lt;p&gt;For migrations, I prefer to run them each time I use the container, in case there has been a change. &lt;/p&gt;

&lt;p&gt;I also run the seeders at this point to populate the database with any required data or test data.&lt;/p&gt;

&lt;p&gt;Since I want the command to always run, I'll add it to a &lt;strong&gt;command&lt;/strong&gt; entry on the .gitpod.yml file.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;image:
  file: .gitpod.Dockerfile
tasks:
  - init: mysql -u root -e "create database trivyeah" &amp;amp;&amp;amp; cp .env.example .env &amp;amp;&amp;amp; composer install &amp;amp;&amp;amp; npm install &amp;amp;&amp;amp; php artisan key:generate
    &lt;strong&gt;command: php artisan migrate --seed&lt;/strong&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Apart from running each time we run our environment, &lt;strong&gt;command&lt;/strong&gt; task entries have another key differences from &lt;strong&gt;init&lt;/strong&gt; tasks. &lt;/p&gt;

&lt;p&gt;An init task expects to end. Long running processes such as running a development server or continuously compiling assets are not suited for init tasks. Command tasks on the other hand can run for as long as the environment is running and are suited to such tasks above.&lt;/p&gt;

&lt;h3&gt;Run Development Server&lt;/h3&gt;

&lt;p&gt;We can run the development server on Gitpod as well. We'll want to run it after migrations are done.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;image:
  file: .gitpod.Dockerfile
tasks:
  - init: mysql -u root -e "create database trivyeah" &amp;amp;&amp;amp; cp .env.example .env &amp;amp;&amp;amp; composer install &amp;amp;&amp;amp; npm install &amp;amp;&amp;amp; php artisan key:generate
    command: php artisan migrate --seed &lt;strong&gt;&amp;amp;&amp;amp; php artisan serve&lt;/strong&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Running and exposing a service on Gitpod creates a publicly accessible URL, similar to ngrok, of the form &lt;strong&gt;&amp;lt;PORT&amp;gt;-&amp;lt;GITPOD-CONTAINER-ID&amp;gt;. gitpod.io&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There's a small problem with our current setup though. Laravel uses the value of &lt;code&gt;$_SERVER['HTTP']&lt;/code&gt; to generate URLs and Routes. This value will be set to localhost:8000 and not to the correct Gitpod URL.&lt;/p&gt;

&lt;p&gt;To work around this, we'll set our APP_URL in .env to our Gitpod URL and then instruct Laravel to use that value to generate URLs and Routes.&lt;/p&gt;

&lt;p&gt;We'll update our &lt;strong&gt;.env.example&lt;/strong&gt; to the following:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;APP_NAME="Your App Name"
APP_ENV=local
APP_KEY=
APP_DEBUG=true
&lt;strong&gt;APP_URL=&lt;/strong&gt;
...&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Gitpod loads some environment variables. You can run &lt;code&gt;env&lt;/code&gt; on the terminal to see all environment variables. &lt;/p&gt;

&lt;p&gt;One of them is &lt;strong&gt;GITPOD_WORKSPACE_URL&lt;/strong&gt; which is the same as the one in your browser when you launch a workspace. We'll need to write the variable into our &lt;strong&gt;.env&lt;/strong&gt; file.&lt;/p&gt;

&lt;p&gt;We'll use the bash utility &lt;code&gt;sed&lt;/code&gt; for this. Essentially, we'll do two replacements. One to put in the workspace URL and another to add the port number in front.&lt;br&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; sed -i "s|APP_URL=|APP_URL=${GITPOD_WORKSPACE_URL}|g" .env &amp;amp;&amp;amp; sed -i "s|APP_URL=https://|APP_URL=https://8000-|g" .env&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The first pass replaces &lt;strong&gt;"APP_URL="&lt;/strong&gt; with &lt;strong&gt;"APP_URL=https://&amp;lt;your-workspace-id&amp;gt;.gitpod.io" &lt;/strong&gt;and the second pass replaces &lt;strong&gt;"APP_URL=https://"&lt;/strong&gt; with &lt;strong&gt;"APP_URL=https://8000-"&lt;/strong&gt;&lt;br&gt;&lt;br&gt;We'll now add this to our init entry in &lt;strong&gt;.gitpod.yml&lt;/strong&gt; so that it happens right after our &lt;strong&gt;.env&lt;/strong&gt; file is created.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;image:
  file: .gitpod.Dockerfile
tasks:
  - init: mysql -u root -e "create database trivyeah" &amp;amp;&amp;amp; cp .env.example .env &amp;amp;&amp;amp; &lt;strong&gt;sed -i "s|APP_URL=|APP_URL=${GITPOD_WORKSPACE_URL}|g" .env &amp;amp;&amp;amp; sed -i "s|APP_URL=https://|APP_URL=https://8000-|g" .env &amp;amp;&amp;amp;&lt;/strong&gt; composer install &amp;amp;&amp;amp; npm install &amp;amp;&amp;amp; php artisan key:generate
    command: php artisan migrate --seed &amp;amp;&amp;amp; php artisan serve&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That init hook has gotten quite unwieldy and we'll address it shortly. In the interim, we'll need to add some code in our &lt;strong&gt;AppServiceProvider&lt;/strong&gt; to force Laravel to use our APP_URL to generate URLs and Routes.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; public function boot()
    {
        \URL::forceRootUrl(\Config::get('app.url'));
        if (\Str::contains(\Config::get('app.url'), 'https://')) {
            \URL::forceScheme('https');
        }
    }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The code we've added forces Laravel to use the &lt;strong&gt;app.url&lt;/strong&gt; config entry (which is gotten from .env's APP_URL) as the root URL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Warning: If you use an older version of Laravel &lt;/strong&gt;the &lt;code&gt;\Str::contains()&lt;/code&gt; method won't work and you'll have to use the string helper &lt;code&gt;str_contains()&lt;/code&gt; instead.&lt;/p&gt;

&lt;h3&gt;Cleaning Up .gitpod.yml &lt;/h3&gt;

&lt;p&gt;The init entry in our Gitpod configuration file is messy. We can move all that to a bash script so that it's more readable. &lt;/p&gt;

&lt;p&gt;Let's create a &lt;strong&gt;.gitpod-init.sh&lt;/strong&gt; file in the root of our project and copy everything in our init entry there.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;mysql -u root -e "create database trivyeah"
cp .env.example .env
sed -i "s|APP_URL=|APP_URL=${GITPOD_WORKSPACE_URL}|g" .env
sed -i "s|APP_URL=https://|APP_URL=https://8000-|g" .env
composer install
npm i
php artisan key:generate&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And finally, we'll update our &lt;strong&gt;.gitpod.yml&lt;/strong&gt; to use this command&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;image:
  file: .gitpod.Dockerfile
tasks:
  - init: &lt;strong&gt;bash .gitpod-init.sh&lt;/strong&gt;
    command: php artisan migrate --seed &amp;amp;&amp;amp; php artisan serve&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Careful with the filenames. Watch the “&lt;strong&gt;.&lt;/strong&gt;” in front.&lt;/p&gt;

&lt;p&gt;Everything should work now.&lt;/p&gt;

&lt;h3&gt;Running our environment&lt;/h3&gt;

&lt;p&gt;At this point, we can push to our repository and run the environment. If you already had a workspace for this repo and branch, you can delete it by going to &lt;a href="https://gitpod.io/workspaces"&gt;https://gitpod.io/workspaces&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now we can create and test a new workspace by going to  &lt;strong&gt;"gitpod.io/#https://github.com/&amp;lt;org-name&amp;gt;/&amp;lt;repo-name&amp;gt;"&lt;/strong&gt; as we described at the beginning of the article.&lt;/p&gt;

&lt;p&gt;If everything works as it should, we can add a badge to the &lt;strong&gt;Readme.md&lt;/strong&gt; that can be clicked to launch the workspace.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/&amp;lt;org-name&amp;gt;/&amp;lt;repo-name&amp;gt;)&lt;/code&gt; &lt;/pre&gt;

&lt;p&gt;Our Laravel project is now Gitpod enabled and can deploy ready-to-code environments in one click.&lt;/p&gt;

&lt;p&gt;Many thanks to &lt;a rel="noreferrer noopener" href="https://twitter.com/gabrielnwogu"&gt;Gabriel Nwogu&lt;/a&gt; for testing this out and suggesting changes.&lt;/p&gt;

</description>
      <category>tools</category>
      <category>docker</category>
      <category>containerization</category>
      <category>devops</category>
    </item>
    <item>
      <title>5 Tools that add color to my Web Apps</title>
      <dc:creator>Etinosa Obaseki</dc:creator>
      <pubDate>Thu, 21 May 2020 11:54:48 +0000</pubDate>
      <link>https://dev.to/obasekietinosa/5-tools-that-add-color-to-my-web-apps-25lo</link>
      <guid>https://dev.to/obasekietinosa/5-tools-that-add-color-to-my-web-apps-25lo</guid>
      <description>&lt;p&gt;I'm bad with colors. It's one of those facts of Life, sorta how the sky is blue or pigs don't fly. It's one of my greatest artistic weakness (along with my inability to draw straight lines).&lt;/p&gt;

&lt;p&gt;However, humans are not the dominant species on the planet because of their ability or lack thereof, but because of their development and use of tools.&lt;/p&gt;

&lt;p&gt;So, in the spirit of the human spirit (🤫) of overcoming our inherent limitations, here are the tools I use to improve my &lt;em&gt;color grade&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;1. Coolors.co&lt;/h2&gt;

&lt;p&gt;Coolors is a great tool for generating cool looking and complementary color schemes. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kvS8Y2GB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://services.etin.space/notes/wp-content/uploads/2020/01/Screenshot-2020-01-04-at-1.34.39-PM-1024x525.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kvS8Y2GB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://services.etin.space/notes/wp-content/uploads/2020/01/Screenshot-2020-01-04-at-1.34.39-PM-1024x525.png" alt="" width="880" height="451"&gt;&lt;/a&gt;Coolors.co Interface&lt;/p&gt;

&lt;p&gt;It allows you ‘lock’ a color (or several) and then generate other colors that would go well with it or alternatively, generate your entire palette from scratch.&lt;/p&gt;

&lt;p&gt;It also has a really cool feature for extracting color palettes from images.&lt;/p&gt;

&lt;p&gt;Check it out &lt;a href="https://coolors.co" rel="noreferrer noopener"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;2. Material.io Color Tool &lt;/h2&gt;

&lt;p&gt;Material Design isn't the dad it was a few years ago, but it remains hugely relevant as an approach to designing modern interfaces.&lt;/p&gt;

&lt;p&gt;The Color Tool from Material.io allows you select a primary and secondary color and then let's you preview how these will look on different material design inspired layouts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yLGeNT07--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://services.etin.space/notes/wp-content/uploads/2020/01/Screenshot-2020-01-04-at-1.36.35-PM-1024x526.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yLGeNT07--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://services.etin.space/notes/wp-content/uploads/2020/01/Screenshot-2020-01-04-at-1.36.35-PM-1024x526.png" alt="" width="880" height="452"&gt;&lt;/a&gt;The Color Tool from Material.io&lt;/p&gt;

&lt;p&gt;The tool also provided tips on readability based on the color scheme you've selected. &lt;/p&gt;

&lt;p&gt;Link &lt;a href="https://material.io/resources/color/#!/" rel="noreferrer noopener"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;3. Material Palette&lt;/h2&gt;

&lt;p&gt;Material Palette is another Material Design oriented tool. This one is a bit more interesting than the former in that it actively alters the colors you pick to make them fit better.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4xSFo-EG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://services.etin.space/notes/wp-content/uploads/2020/01/Screenshot-2020-01-04-at-1.35.25-PM-1024x523.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4xSFo-EG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://services.etin.space/notes/wp-content/uploads/2020/01/Screenshot-2020-01-04-at-1.35.25-PM-1024x523.png" alt="" width="880" height="449"&gt;&lt;/a&gt;Material Palette's generator.&lt;/p&gt;

&lt;p&gt;After you pick two colors, it generates a palette of eight colors along with recommendations on how and where they should be used.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.materialpalette.com/" rel="noreferrer noopener"&gt;Link&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;4. uiGradients&lt;/h2&gt;

&lt;p&gt;UIGradients provides a wide range of premade gradient backgrounds and allows you either download as an image or get the CSS rules to create the gradient in your app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JvGfAf_y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://services.etin.space/notes/wp-content/uploads/2020/01/Screenshot-2020-01-04-at-1.43.33-PM-1024x525.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JvGfAf_y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://services.etin.space/notes/wp-content/uploads/2020/01/Screenshot-2020-01-04-at-1.43.33-PM-1024x525.png" alt="" width="880" height="451"&gt;&lt;/a&gt;uiGradient's selection&lt;/p&gt;

&lt;p&gt;Gradients are great alternative to solid color backgrounds, although you'll need to be careful to ensure that your app maintains it's readability.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://uigradients.com/#Flare" rel="noreferrer noopener"&gt;Check it out&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;5. Subtle Patterns by TopTal&lt;/h2&gt;

&lt;p&gt;Sometimes, I want to break the monotony of solid color backgrounds with getting anything too extravagant. &lt;/p&gt;

&lt;p&gt;Subtle Patterns are great for that. The repository of several background images is maintained by TopTal and has found plenty of use in many of my projects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--H7U54qs---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://services.etin.space/notes/wp-content/uploads/2020/01/Screenshot-2020-01-04-at-1.41.43-PM-1024x526.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--H7U54qs---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://services.etin.space/notes/wp-content/uploads/2020/01/Screenshot-2020-01-04-at-1.41.43-PM-1024x526.png" alt="" width="880" height="452"&gt;&lt;/a&gt;Toptal's Subtle Patterns&lt;/p&gt;

&lt;p&gt;The site allows you search for patterns and offers a live preview of each background.&lt;/p&gt;

&lt;p&gt;Convinced? &lt;a rel="noreferrer noopener" href="https://www.toptal.com/designers/subtlepatterns/"&gt;Give it a try.&lt;/a&gt;&lt;/p&gt;








&lt;p&gt;Do you have different tools that you use to help with color/design issues in your web apps? I'd love to hear about them. I need all the help I can get. 😅.&lt;/p&gt;

&lt;p&gt;Hit me up on Twitter! &lt;a href="https://twitter.com/obasekietinosa" rel="noreferrer noopener"&gt;@obasekietinosa&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tools</category>
      <category>design</category>
    </item>
    <item>
      <title>Running Scheduled Firebase Functions Locally</title>
      <dc:creator>Etinosa Obaseki</dc:creator>
      <pubDate>Tue, 19 May 2020 22:58:09 +0000</pubDate>
      <link>https://dev.to/obasekietinosa/running-scheduled-firebase-functions-locally-am8</link>
      <guid>https://dev.to/obasekietinosa/running-scheduled-firebase-functions-locally-am8</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; Use&lt;code&gt; $ firebase functions:shell&lt;/code&gt; and then type in the name of your function (tab autocomplete is available) along with any arguments you need to pass and press enter. You receive the output to the console.&lt;/p&gt;

&lt;p&gt;While developing Firebase Functions, we need to run them locally to ensure that everything works as we might expect before we deploy the function to the cloud.&lt;/p&gt;

&lt;p&gt;For HTTP Functions, it's a straightforward process to run &lt;code&gt;$ firebase serve&lt;/code&gt; in the terminal and then visit the browser.&lt;/p&gt;

&lt;p&gt;Firebase Scheduled Functions can have one of several triggers (similar to HTTP Functions that are triggered by a HTTP Request).&lt;/p&gt;

&lt;p&gt;The problem is that we often cannot set up the trigger for Scheduled Functions the way we can for HTTP Functions.&lt;/p&gt;

&lt;p&gt;For example, with the PubSub triggers it would be impractical to try to set up a pubslisher-subscribe system on our local environments and test that our functions run every minute as prescribed.&lt;/p&gt;

&lt;p&gt;We'll instead leave that to the Firebase team. Instead, we want to test that our functions executes as it should.&lt;/p&gt;

&lt;p&gt;Use&lt;code&gt; $ firebase functions:shell&lt;/code&gt; and then type in the name of your function (tab autocomplete is available) along with any arguments you need to pass and press enter. You receive the output to the console.&lt;/p&gt;

</description>
      <category>firebase</category>
      <category>local</category>
    </item>
    <item>
      <title>If vs Ternary vs Switch-Case for conditionals</title>
      <dc:creator>Etinosa Obaseki</dc:creator>
      <pubDate>Tue, 12 May 2020 19:46:48 +0000</pubDate>
      <link>https://dev.to/obasekietinosa/if-vs-ternary-vs-switch-case-for-conditionals-2841</link>
      <guid>https://dev.to/obasekietinosa/if-vs-ternary-vs-switch-case-for-conditionals-2841</guid>
      <description>&lt;p&gt;Conditionals are programming structures that determine the flow of the program based on an evaluation.&lt;/p&gt;

&lt;p&gt;In most C-style languages, such as JavaScript, there are multiple ways of handling conditional logic.&lt;/p&gt;

&lt;p&gt;In this article, I'll discuss the &lt;code&gt;if-else&lt;/code&gt;, ternary operator, &lt;code&gt;?&lt;/code&gt;  and &lt;code&gt;switch-case&lt;/code&gt; and how I decide which to use for different situations.&lt;/p&gt;

&lt;p&gt;Whenever I write code that will need to be maintained either by myself or someone else, I like to consider the &lt;em&gt;developer experience&lt;/em&gt; of that code.&lt;/p&gt;

&lt;p&gt;Will I (or the eventual maintained) easily be able to grasp the purpose of the code? Am I likely to misunderstand what the code actually does? Does the code significantly deviate from expected affordance?&lt;/p&gt;

&lt;h2&gt;If-Else vs Ternary&lt;/h2&gt;

&lt;pre&gt;let isEvenOrOdd = number =&amp;gt; {
    if(number % 2 == 0){
        return "Is Even"
    }
    else {
        return "Is Odd"
    }
}&lt;/pre&gt;

&lt;p&gt;For scenarios with this-or-that (only two possible) outcomes, I prefer to use a ternary because it's less code for the maintainer to parse. In a large project, those could be a lot of lines saved.&lt;/p&gt;

&lt;pre&gt;let isEvenOrOdd = number =&amp;gt; {
    return number % 2 == 0 ? 
        "Is Even" : "Is Odd"
}&lt;/pre&gt;

&lt;p&gt;However, for more complex conditionals  we may need &lt;code&gt;else if&lt;/code&gt;s &lt;/p&gt;

&lt;p&gt;For example, a conditional with three possible options.&lt;/p&gt;

&lt;pre&gt;let meal = null
if(time == "morning") {
    meal = "breakfast"
} else if(time == "afternoon") {
    meal = "lunch"
} else {
    meal = "dinner"
}&lt;/pre&gt;

&lt;p&gt;We could handle this case with a ternary operator(s) as well.&lt;/p&gt;

&lt;pre&gt;let meal = null
time == "morning" ?
    meal = "breakfast"
    :
    time == "afternoon" ?
        meal = "lunch"
        :
        meal = "dinner"&lt;/pre&gt;

&lt;p&gt;Of course, despite looking fancier than ordinary If-Elses, this is probably less readable than the previous example.&lt;/p&gt;

&lt;p&gt;Let's switch this up a bit.&lt;/p&gt;

&lt;h2&gt;Switch Statements&lt;/h2&gt;

&lt;p&gt;Switch Statements allow us to evaluate several cases against a single expression. &lt;/p&gt;

&lt;p&gt;Our meal example from above would be represented thus:&lt;/p&gt;

&lt;pre&gt;let meal = null
switch(time) {
    case "morning":
        meal = "breakfast"
        break
    case "afternoon":
        meal = "lunch"
        break
    default:
        meal = "dinner"
}&lt;/pre&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Switch statements are versatile and could provide a more readable alternative to If-Elses and ternary operators.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Pain of Multimedia in HTML Emails</title>
      <dc:creator>Etinosa Obaseki</dc:creator>
      <pubDate>Wed, 06 May 2020 07:47:18 +0000</pubDate>
      <link>https://dev.to/obasekietinosa/the-pain-of-multimedia-in-html-emails-2hpm</link>
      <guid>https://dev.to/obasekietinosa/the-pain-of-multimedia-in-html-emails-2hpm</guid>
      <description>&lt;h4&gt;
  
  
  I gave a talk at Frontstack this year and it was an amazing experience. I'm sharing the essence of my talk here ICYMI and also because I write better than I speak sometimes, so you might enjoy this more.
&lt;/h4&gt;

&lt;p&gt;I'll start off with a quick introduction. &lt;a href="https://etin.space"&gt;I'm Etin Obaseki&lt;/a&gt;, Software Engineer whose current life motto is &lt;a href="https://notes.etin.space/posts/who-is-etinosa-obaseki"&gt;Life, Learn, Loop.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Multimedia across the web has come in leaps and bounds. We can now easily use various forms of media all across the web almost ubiquitously. Videos, audio, animation. All sorts of wonderful things.&lt;/p&gt;

&lt;p&gt;What about emails? Emails are notoriously hard to make look good for a number of reasons. Multimedia is a definite no. &lt;em&gt;Or is it?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What can we do right now? What will the email of the future look like? Let’s find out.&lt;/p&gt;








&lt;h2&gt;The Introduction&lt;/h2&gt;





&lt;p&gt;We've all sent emails. Whether it's to let friends and family know how you're doing or to express your 'slight confusion' to a colleague at work or to rail at the customer service unit of your bank for yet another unexplained debit.&lt;/p&gt;

&lt;p&gt;The emails we'll be discussing today though are more the kind sent out by brands to their audience. Whether it's a newsletter or a service notification, we'll be discussing if and how we can spruce up that email with multimedia.&lt;/p&gt;

&lt;p&gt;If you've ever designed and sent out HTML emails, you'll know just how terrible they can be to write and test.&lt;/p&gt;

&lt;p&gt;Thankfully, there are more and more tools that make this process a breeze and I share some of my favourite here.&lt;/p&gt;








&lt;h2&gt;My First Foray into Emails&lt;/h2&gt;





&lt;p&gt;At my first job, I had to build and send our newsletter. My boss had a couple of requirements for the newsletter including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A two column layout&lt;/li&gt;
&lt;li&gt;News articles and featured images on each column&lt;/li&gt;
&lt;li&gt;Videos from YouTube&lt;/li&gt;
&lt;li&gt;A Twitter Feed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wrote an entire article on the lesson in humility that this was.&lt;/p&gt;

&lt;p&gt;But, in summary, my first few attempts turned out poorly.&lt;/p&gt;

&lt;p&gt;I had not written a HTML email before that, but I figured it would be easy because I had built one or two websites.&lt;/p&gt;

&lt;p&gt;It wasn't and I learnt the first two lessons of my career:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Don't overestimate yourself (although, sadly, it hasn't stuck as much as I would have liked.) and &lt;/li&gt;
&lt;li&gt;Email != Web&lt;/li&gt;
&lt;/ol&gt;








&lt;h2&gt;Email != Web&lt;/h2&gt;





&lt;p&gt;Although, nowadays, we get our emails over the web, they are different platforms. &lt;/p&gt;

&lt;p&gt;Email clients and web browsers evolved very different and as such there are wide variations on the things they can do and how they go about doing those things.&lt;/p&gt;

&lt;h2&gt;What can’t we do with Emails?&lt;/h2&gt;

&lt;p&gt;I've outlined some of the most jarring not-haves I have encountered while building emails.&lt;/p&gt;

&lt;h3&gt;No JavaScript&lt;/h3&gt;

&lt;p&gt;Most email clients will, for security reasons, not run any JavaScript at all in your email. So you absolutely cannot rely on any JS tricks for anything in your email.&lt;/p&gt;

&lt;h3&gt;Embed iFrames&lt;/h3&gt;

&lt;p&gt;One of the requirements for my first email was embedding a “featured video” from our YouTube channel within the email.&lt;/p&gt;

&lt;p&gt;iFrames will be blocked by most email clients as they'll usually contain scripts and could pose a security flaw.&lt;/p&gt;

&lt;h3&gt;Use HTML5 tags/features&lt;/h3&gt;

&lt;p&gt;Because most email clients haven't kept up with the times HTML 5 tags and features will not work here.&lt;/p&gt;

&lt;h3&gt;Use flexbox, CSS grid or even floats for layout&lt;/h3&gt;

&lt;p&gt;Emails use tables for their layouts. No flexbox, no grid. Not even those clever hacks with floats and clearfixes. If you want layouts use tables.&lt;/p&gt;

&lt;h3&gt;Embed audio or video content&lt;/h3&gt;

&lt;p&gt;No MULTIMEDIA support!!! &lt;/p&gt;

&lt;p&gt;Although multimedia support is non-existent on email, it does support most picture formats quite well and it is one of these that will end up saving everything. The GIF.&lt;/p&gt;

&lt;h2&gt;GIF Things Up!&lt;/h2&gt;

&lt;p&gt;GIFs are a great way to add interactivity to our emails.&lt;/p&gt;

&lt;p&gt;Similar to the ways we use them on social media, we can add a lot of meaning and context to our emails by creatively applying GIFs.&lt;/p&gt;

&lt;p&gt;It is important to note that images may not always load on an email and so we must design conscious of this point of failure and degrade gracefully in instances where images are not available.&lt;/p&gt;

&lt;p&gt;Here are a few clever GIF uses in emails I've seen or thought up.&lt;/p&gt;

&lt;h3&gt;A Countdown Timer&lt;/h3&gt;

&lt;p&gt;I first saw this done on a marketing email encouraging me to buy at a discounted price before the deadline. And there was a countdown timer right in the email.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FzJGizkX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://services.etin.space/notes/wp-content/uploads/2020/04/KpOtd.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FzJGizkX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://services.etin.space/notes/wp-content/uploads/2020/04/KpOtd.gif" alt="" width="494" height="120"&gt;&lt;/a&gt;A countdown timer GIF&lt;/p&gt;

&lt;p&gt;The trick is to have a GIF that counts down for long enough for your users to read your email, say 60 seconds and then update that GIF each time.&lt;/p&gt;

&lt;p&gt;&lt;a rel="noreferrer noopener" href="https://stackoverflow.com/a/13597274/5381731"&gt;This StackOverflow answer&lt;/a&gt;, also the source of the GIF above, does a great job of explaining the implementation. Alternatively, you could use a service like &lt;a href="https://cloudinary.com" rel="noreferrer noopener"&gt;Cloudinary&lt;/a&gt; to create a GIF that continuously updates its countdown time.&lt;/p&gt;

&lt;h3&gt;Signature/Text Animation&lt;/h3&gt;

&lt;p&gt;What better way to close off your email than with a personal touch?&lt;/p&gt;

&lt;p&gt;A GIF of you signing your name would be very cool (I, at least, would find it very much so).&lt;/p&gt;

&lt;p&gt;You could also use it to call attention to your headings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UuKJ_54K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://services.etin.space/notes/wp-content/uploads/2020/04/Vanilla-0.5s-251px.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UuKJ_54K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://services.etin.space/notes/wp-content/uploads/2020/04/Vanilla-0.5s-251px.gif" alt="" width="251" height="61"&gt;&lt;/a&gt;Yes. This text shaking in different colors is pretty cool. Made with &lt;a href="https://loading.io" rel="noreferrer noopener"&gt;Loading.io&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Animated/Specially Shaped Buttons&lt;/h3&gt;

&lt;p&gt;We can make our call-to-actions more appealing by adding animations to them. CSS animations might not work on your email client though and so once more GIFs come to our rescue.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uHRUUMP7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://services.etin.space/notes/wp-content/uploads/2020/04/animated-button-image-0328.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uHRUUMP7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://services.etin.space/notes/wp-content/uploads/2020/04/animated-button-image-0328.gif" alt="" width="150" height="150"&gt;&lt;/a&gt;An Enter Button. &lt;a href="https://www.animatedimages.org/img-animated-button-image-0328-88732.htm"&gt;https://www.animatedimages.org/img-animated-button-image-0328-88732.htm&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We simply create a GIF that looks like the button we want and wrap the image in an &lt;code&gt;&amp;lt;a&amp;gt;&amp;lt;/a&amp;gt;&lt;/code&gt; tag.&lt;/p&gt;

&lt;h3&gt;Video Previews&lt;/h3&gt;

&lt;p&gt;Another potential use case for GIF is to preview videos. We could put a short clip as a GIF and allow people link to the full video by clicking.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fhLZ6E9M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://services.etin.space/notes/wp-content/uploads/2020/04/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fhLZ6E9M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://services.etin.space/notes/wp-content/uploads/2020/04/giphy.gif" alt="" width="500" height="255"&gt;&lt;/a&gt;&lt;em&gt;Hakuna Matata&lt;/em&gt;. GIF from Disney's The Lion King&lt;/p&gt;

&lt;p&gt;Unfortunately, there's no way to include audio that I know of.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;I hope that this gives you some ideas for your next email. If you come up with something cool, I'd love to see it. &lt;a href="https://twitter.com/obasekietinosa" rel="noreferrer noopener"&gt;Hit me up on Twitter&lt;/a&gt; and share!&lt;/p&gt;

</description>
      <category>html</category>
      <category>emails</category>
      <category>multimedia</category>
    </item>
    <item>
      <title>Database Operations on the Firebase Realtime Database using the JS SDK</title>
      <dc:creator>Etinosa Obaseki</dc:creator>
      <pubDate>Tue, 28 Apr 2020 16:07:15 +0000</pubDate>
      <link>https://dev.to/obasekietinosa/database-operations-on-the-firebase-realtime-database-using-the-js-sdk-1b3a</link>
      <guid>https://dev.to/obasekietinosa/database-operations-on-the-firebase-realtime-database-using-the-js-sdk-1b3a</guid>
      <description>&lt;p&gt;Google’s Firebase allows us the ability to run our backend infrastructure without actually managing said infrastructure.&lt;/p&gt;

&lt;p&gt;Some of the services Firebase offers include Cloud Functions for running backend code, Authentication and Databases&lt;/p&gt;

&lt;p&gt;There are two database offerings in the Firebase console: The real-time database and the cloud database. This article is focused on basic operations on the real time database.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Realtime Database
&lt;/h1&gt;

&lt;p&gt;The Firebase Realtime Database is a managed NoSQL database service. As with other Firebase services, we do not need to worry about managing the underlying infrastructure or resources.&lt;/p&gt;

&lt;p&gt;Being a NoSQL database, the data is not stored in a relational (tabular) form but instead uses a document model in JSON format. Data is stored in key-value pairs.&lt;/p&gt;

&lt;p&gt;The Realtime Database showing the root node and children nodes&lt;br&gt;
This same data represented in JSON would be as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;games&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-M5GU2j383E8MaXXbLT3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;current_quesion&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;latest_tweet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1251784979954241536&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;start_tweet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1251784906830733315&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AnxiousEtin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ObasekiEtinosa&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tetrazoid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

      &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The root node (&lt;strong&gt;trivyeah-twitter-client&lt;/strong&gt;) contains the child node games which holds &lt;strong&gt;-M5GU2j383E8MaXXbLT3&lt;/strong&gt; as a child. That node has several nodes with concrete values (such as &lt;strong&gt;current_question&lt;/strong&gt; with 0) but also contains a node users with children of its own.&lt;/p&gt;

&lt;h1&gt;
  
  
  References and Paths
&lt;/h1&gt;

&lt;p&gt;Interaction with the database is done via references. A reference is a pointer to a particular node on the database. This reference will allow use access the data stored on that node, it’s children and perform operations on the node.&lt;/p&gt;

&lt;p&gt;Using the &lt;code&gt;firebase-admin&lt;/code&gt; package, we’ll get a reference to the DB.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;db now holds a reference to the root, in the above example &lt;strong&gt;trivyeah-twitter-client&lt;/strong&gt;, of our database and we can perform any operations on it.&lt;/p&gt;

&lt;p&gt;If we instead wanted a reference to some other node on the document, we would pass a path to the desired node to the &lt;code&gt;ref()&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;gameDb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;games&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code would give us a reference to the games node. To get a more deeply nested node pass the path separated by slashes e.g ref('games/-M5GU2j383E8MaXXbLT3/users')&lt;/p&gt;

&lt;p&gt;We can also achieve this by using the child() method on any database reference. By passing in a path to any child node we want, we can get a reference to that node.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;gameDb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;games&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;childNodeUsersDb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gameDb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;games/-M5GU2j383E8MaXXbLT3/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Database Operations
&lt;/h1&gt;

&lt;p&gt;The four basic functions of persistent storage are &lt;strong&gt;Create&lt;/strong&gt;, &lt;strong&gt;Read&lt;/strong&gt;, &lt;strong&gt;Update&lt;/strong&gt; and &lt;strong&gt;Delete&lt;/strong&gt;. Let’s look at each of these operations on the Firebase Realtime Database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create Operations
&lt;/h2&gt;

&lt;p&gt;Create operations persistent a new record to storage. In the Realtime Database the set method is the basic write operation. There are two different ways of using it and will be shown here.&lt;/p&gt;

&lt;h3&gt;
  
  
  (Over)Writing to a Path
&lt;/h3&gt;

&lt;p&gt;Using the set method will write data to the location specified, if there was any data at that location, it will be overwritten.&lt;/p&gt;

&lt;p&gt;It takes any JavaScript value as its first argument and this value will be persisted. From the official documentation, &lt;em&gt;“You can pass set a string, number, boolean, null, array or any JSON object.“&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;foodDb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;breakfast&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;foodDb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;cereal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;calories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Great for when you're in a hurry&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nl"&gt;fufu&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;calories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cheap, but long lasting. Really long&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example above sets everything at the breakfast node to the object we passed in. Anything that may have been there before is overwritten.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding Data to a Node
&lt;/h3&gt;

&lt;p&gt;To add data to a node that already contains data without overwriting the data already on the node, we use the push() method. It returns a reference to a newly created child node on the originally referenced node.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;mealsDb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;meals&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;newMeal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mealDb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;//newMeal will hold the reference to the new record and can be set without overwriting it's siblings&lt;/span&gt;

&lt;span class="nx"&gt;newMeal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; 
&lt;span class="c1"&gt;//returns the key for the new record. Something like "-M5GU2j383E8MaXXbLT3"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We may then use the set() method on this new reference.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;mealsDb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;meals&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;newMeal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mealDb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nx"&gt;newMeal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;timeOfDay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;morning&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;mealEaten&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fufu&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="na"&gt;stomachStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bloated&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;caloriesGained&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you don’t need the reference of the new node for any other operations, you can chain the &lt;code&gt;push()&lt;/code&gt; and &lt;code&gt;set()&lt;/code&gt; calls.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;mealsDb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;meals&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;newMeal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mealDb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;timeOfDay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;morning&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;mealEaten&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fufu&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="na"&gt;stomachStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bloated&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;caloriesGained&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cases where you need to append to a node using your own key is considered an update action. Let’s look at what those are like.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update Operations
&lt;/h2&gt;

&lt;p&gt;Update operations append data to the reference specified without overwriting any other properties.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;meals&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-K5GU2p242E8MaXHbQT1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nl"&gt;timeOfDay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;morning&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;mealEaten&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fufu&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;stomachStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bloated&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;caloriesGained&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-K5GU2r322X8YadRZQT1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nl"&gt;timeOfDay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;afternoon&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;mealEaten&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cornflakes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="nx"&gt;stomachStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;slightlyFull&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;caloriesGained&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assuming we had the above in our database and we intend to add to the meals node without affecting any of its existing children, we would pass an object containing our desired key to the &lt;code&gt;update()&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;mealsDb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;meals&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;newMeal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mealDb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;uniqueMealKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;timeOfDay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;evening&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;mealEaten&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nightcap&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="na"&gt;stomachStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;light&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;caloriesGained&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Read Operations
&lt;/h2&gt;

&lt;p&gt;The JS SDK supports non-blocking reads and has several events that prompt a read. The &lt;code&gt;on()&lt;/code&gt; method takes the event we want to listen to as the first argument and a callback where we can access a snapshot of the data as the second argument.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The callback we pass to the &lt;code&gt;on()&lt;/code&gt; method is fired every time our event takes place but if you only want to perform the read and the associated callback a single time then use the &lt;code&gt;once()&lt;/code&gt; method instead. Both methods have identical signatures.&lt;/p&gt;

&lt;p&gt;The events we can perform read on are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“value”&lt;/li&gt;
&lt;li&gt;“child_added”&lt;/li&gt;
&lt;li&gt;“child_changed”&lt;/li&gt;
&lt;li&gt;“child_removed”&lt;/li&gt;
&lt;li&gt;“child_moved”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sticking with our &lt;strong&gt;meals&lt;/strong&gt; node, we can retrieve all the meals using the value event.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;mealsDb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;meals&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;mealDb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;once&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;meals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;on()&lt;/code&gt;/&lt;code&gt;once()&lt;/code&gt; is an asynchronous method and accepts a callback.&lt;/p&gt;

&lt;p&gt;When the database call is complete, the callback is fired and passed a DataSnapshot instance. This object contains the state of the database at the moment that the event ("value" in this case) was fired. We can call the &lt;code&gt;val()&lt;/code&gt; method on the snapshot to get a JavaScript object (or primitive value) representing the values of the node reference that the event was called on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-K5GU2p242E8MaXHbQT1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;timeOfDay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;morning&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;mealEaten&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fufu&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;stomachStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bloated&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;caloriesGained&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-K5GU2r322X8YadRZQT1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;timeOfDay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;afternoon&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;mealEaten&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cornflakes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;stomachStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;slightlyFull&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;caloriesGained&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;uniqueMealKey&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;timeOfDay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;evening&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;mealEaten&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nightcap&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;stomachStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;light&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;caloriesGained&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We would get the above JavaScript object in our meals variable and could then carry out what ever actions we wanted on it.&lt;/p&gt;

&lt;p&gt;On the &lt;code&gt;DataSnapshot&lt;/code&gt; instance, there are other methods available. You can view them in the documentation here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Delete Operations
&lt;/h2&gt;

&lt;p&gt;We have covered removing data from a node in passing earlier in the article. To delete a node, simply use the &lt;code&gt;set()&lt;/code&gt; method on its reference to set it to &lt;code&gt;null&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;mealsDb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firebaseAdmin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;meals&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;mealDb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;uniqueMealKey&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the &lt;code&gt;child()&lt;/code&gt; method to get a reference to the child node on meals we want to delete, we then call &lt;code&gt;set()&lt;/code&gt; on that reference and pass it null. This will remove all the data on &lt;strong&gt;uniqueMealKey&lt;/strong&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;These are how the basic DB operations are performed on the Firebase Realtime Database using the Firebase JS SDK. The SDK is also available in Java, Go and Python. Although, the Go and Python SDKs perform blocking reads.&lt;/p&gt;

&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;p&gt;Firebase Database Admin Docs – &lt;a href="https://firebase.google.com/docs/database/admin/start"&gt;https://firebase.google.com/docs/database/admin/start&lt;/a&gt;&lt;/p&gt;

</description>
      <category>firebase</category>
      <category>javascript</category>
      <category>nosql</category>
      <category>node</category>
    </item>
    <item>
      <title>My Year in Firebase: Experiences with Building &amp; Deploying on the Platform</title>
      <dc:creator>Etinosa Obaseki</dc:creator>
      <pubDate>Tue, 21 Apr 2020 18:28:53 +0000</pubDate>
      <link>https://dev.to/obasekietinosa/reversing-the-numbering-on-an-ordered-list-with-custom-counters-2df0</link>
      <guid>https://dev.to/obasekietinosa/reversing-the-numbering-on-an-ordered-list-with-custom-counters-2df0</guid>
      <description>&lt;h3&gt;I began using the Firebase platform last year along with a number of other technologies and it has been an interesting ride. I'm going to document my experience here.&lt;/h3&gt;








&lt;h2&gt;Love At First Byte?😍&lt;/h2&gt;





&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--y3ZaTX_z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://services.etin.space/notes/wp-content/uploads/2019/12/Screenshot-2019-12-06-at-9.30.15-AM-1024x419.png" alt="" width="880" height="360"&gt;Firebase's landing page





&lt;p&gt;My introduction to Firebase came when, in 2018, I got a gig to add Google Analytics to a web app (I charged quite a bit for that 😅). The front end was built in the Ionic Framework and hosted on &lt;a href="https://firebase.google.com/docs/hosting"&gt;Firebase Hosting&lt;/a&gt; while the back end was in Java and hosted elsewhere. &lt;/p&gt;

&lt;p&gt;Thinking about it now, it was my earliest exposure to &lt;a href="https://www.quora.com/Why-does-it-make-sense-to-separate-front-end-from-back-end"&gt;Distributed Client-Server Architecture&lt;/a&gt; on the web.  All my prior experience had been with monoliths that served straight to the clients plate.&lt;/p&gt;

&lt;p&gt;I was intrigued. &lt;/p&gt;

&lt;p&gt;I ran &lt;code&gt;git clone&lt;/code&gt; and set up Analytics on the project fairly quickly. &lt;/p&gt;

&lt;p&gt;Time to deploy? Phew. Google to the rescue. The &lt;a href="https://firebase.google.com/docs"&gt;Firebase Docs&lt;/a&gt; were extremely helpful. &lt;br&gt;&lt;/p&gt;

&lt;p&gt;I'd need to install the &lt;a href="https://firebase.google.com/docs/cli"&gt;Firebase CLI&lt;/a&gt;, &lt;code&gt;firebase-tools&lt;/code&gt; using NPM:&lt;/p&gt;

&lt;pre&gt;$ npm install -g firebase-tools&lt;/pre&gt;

&lt;p&gt;And deploying?&lt;/p&gt;

&lt;pre&gt;$ firebase deploy&lt;/pre&gt;

&lt;p&gt;'I was in love!&lt;/p&gt;

&lt;p&gt;Job done and I got paid!&lt;/p&gt;

&lt;p&gt;But, how much does such a great service cost? Absolutely nothing!(With limits, of course 😒).&lt;/p&gt;

&lt;p&gt;Marry me FiFi! &lt;/p&gt;

&lt;h2&gt;Did I get her number?☎️&lt;/h2&gt;

&lt;p&gt;Well, I didn't really think about Firebase much after that. Most of my work was still done in just PHP, so I didn't really have a use for it day-to-day.&lt;/p&gt;

&lt;p&gt;This changed when in November 2018 I had to build a &lt;a href="https://etin.space"&gt;portfolio website&lt;/a&gt; for myself. That's quite an interesting story itself, but the two most relevant parts are that &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I didn't have the money to pay for a domain and (shared) hosting like I usually would for my projects&lt;/li&gt;
&lt;li&gt;I had just begun to learn React from &lt;a href="https://reactforbeginners.com/"&gt;a Wes Bos course&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After building the portfolio website in good time, it was time to set up my project on Firebase.&lt;/p&gt;

&lt;h2&gt;Our First Date💑&lt;/h2&gt;

&lt;p&gt;To set up the project we'll need to head to &lt;a href="https://console.firebase.google.com"&gt;the Firebase Console&lt;/a&gt; and create a new Project. A Firebase Project contains "Apps" which share Firebase resources like Authentication, Database, etcetera. &lt;/p&gt;

&lt;p&gt;After setting up the project on the Console, the next thing to do is initialize Firebase in my portfolio website. We do this by running:&lt;/p&gt;

&lt;pre&gt;$ firebase init&lt;/pre&gt;

&lt;p&gt;A few on screen prompts later, where we select the project we want to work on and the Firebase feature we want to use and voila! We're ready to deploy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mWdTxVNX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://services.etin.space/notes/wp-content/uploads/2019/12/EKI0dU3WwAUvqYO.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mWdTxVNX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://services.etin.space/notes/wp-content/uploads/2019/12/EKI0dU3WwAUvqYO.png" alt="" width="727" height="136"&gt;&lt;/a&gt;Can you feel the fire?&lt;/p&gt;

&lt;p&gt;We also need to specify whether it's a Single Page Application (in which case all requests will be redirected to index) and where our public folder is. In the case of my portofolio app it was the &lt;code&gt;build&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;Now, when we run the &lt;code&gt;firebase deploy&lt;/code&gt; command from earlier, it'll copy the files from the public directory we specified and upload them to the Firebase cloud.&lt;/p&gt;

&lt;h2&gt;We are Live!!! 🎉&lt;/h2&gt;

&lt;p&gt;Once the deploy is successfully done, we get our own URL: &lt;em&gt;https://your-app-name.firebaseapp.com &lt;/em&gt;(and more recently, you also get &lt;em&gt;https://your-app-name.web.app&lt;/em&gt;). &lt;/p&gt;

&lt;p&gt;That was smooth, wasn't it? Connecting to a custom domain is just as easy. Simply navigate to the Hosting tab from your Project page on the Firebase Console and click &lt;strong&gt;Connect Custom Domain.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TCV9Obvc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://services.etin.space/notes/wp-content/uploads/2019/12/Screenshot-2019-12-06-at-11.49.20-AM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TCV9Obvc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://services.etin.space/notes/wp-content/uploads/2019/12/Screenshot-2019-12-06-at-11.49.20-AM.png" alt="" width="229" height="585"&gt;&lt;/a&gt;The Console's sidebar&lt;/p&gt;

&lt;p&gt;You'll need to already own a domain, of course, and be able to update it's DNS Records. The process varies across providers but generally you do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a TXT Record provided in the Console to prove ownership of the domain.&lt;/li&gt;
&lt;li&gt;Add an A record pointing to the Firebase Hosting's public IP&lt;/li&gt;
&lt;li&gt;Add another A record pointing to another Firebase public IP for redundancy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And in 0-48 Hours your domain should be provisioned along with a free SSL certificate.&lt;/p&gt;

&lt;h2&gt;What Else Can This Baby Do? 😉&lt;/h2&gt;

&lt;p&gt;So, that covers Hosting, which was far and away my most used Firebase service this year. But what other goodies does Firebase provide?&lt;/p&gt;

&lt;p&gt;From the sidebar we can already see a lot of things, but my next favourite feature has to be Firebase Databases, specifically the &lt;strong&gt;Realtime Database&lt;/strong&gt;. There's also Cloud Firestore, but I haven't used that yet.&lt;/p&gt;

&lt;h4&gt;The Firebase Realtime Database&lt;/h4&gt;

&lt;p&gt;The Realtime Database is a cloud NoSQL database implementation, which means it's similar to MongoDB. It stores data in an Object-Key format and can access several records very quickly. &lt;/p&gt;

&lt;p&gt;My favourite thing about it? It comes with a REST API right out of the box! Define your data structure and you can access it RESTfully via &lt;em&gt;https://your-app-name.firebase.io/node-name.json&lt;/em&gt; and do all the usual GETs, POSTs, PUTs &amp;amp; DELETEs.&lt;/p&gt;

&lt;p&gt;It saved me the trouble of building a full back end for a few small projects I built in React. &lt;/p&gt;

&lt;p&gt;I also had plenty of joy using Firebase functions to build a Twitter Bot.&lt;/p&gt;

&lt;h4&gt;Cloud Functions for Firebase&lt;/h4&gt;

&lt;p&gt;Firebase Functions allow you run server side code without infrastructure. Serverless, as the kids are calling it these days.&lt;/p&gt;

&lt;p&gt;Inspired by the &lt;a href="https://github.com/shalvah"&gt;numerous bots built by Shalvah&lt;/a&gt;, it allowed me write a NodeJS function to search Twitter for tweets that were a quote by someone famous and upload that quote to the Firebase Database (remember that guy?).&lt;/p&gt;

&lt;p&gt;Typically, I'd have to spin up a server and set up a cron job to fire that function at intervals, but with Cloud Functions I can create a PubSub function that runs on some event (in this case, every 15 minutes).&lt;/p&gt;

&lt;h2&gt;In Conclusion 👋&lt;/h2&gt;

&lt;p&gt;Firebase has become my first choice development platform. It's easy to use and incredibly versatile. &lt;/p&gt;

&lt;p&gt;I'm building a SAAS Product in Q1 2020 and I'm attempting to convince my team that it's what we should use. &lt;/p&gt;

&lt;p&gt;Wish me luck.&lt;/p&gt;

</description>
      <category>firebase</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
