Always buy the latest editions of the programming books

After reading this blog, some of you may say that I was trying to shamelessly promote the book I’m working on, but this was not the goal of this write-up.

Over the years, I’ve authored and co-authored a number of books on programming. In two cases, the publishers asked me to write a second edition. In 2015, the second edition of my Java book was released by Wrox, and this year a second edition of the Angular book is about to be released by Manning.

IMO, the publisher asks the author to write a second edition of a programming book if the following statements are true:

1. The first edition was selling well, and the publisher sees an opportunity for additional revenues
2. A new version of the software has been released, and the first edition became outdated

When I was working on the second edition of my Java book, it became obvious to me that the quality of the materials in the second edition was much better than the first one. Why?

First, while writing a book you spend lots of time researching the subject. The second edition requires more research hence you understand the subject better.

Second, the errors do creep in no matter how many times you and technical editors go through the code samples; there is always something that can be improved or fixed.

Third, the readers of the first edition provide feedback. Some of the feedbacks are just mean (e.g one reader gave me one star on Amazon because the book arrived with scratches), but for the most part, the readers provide constructive criticism, which results in a better quality of the second edition.

Fourth, the more time you try to explain a subject to someone (in the books, blogs, classrooms, or conversations), the better you understand the subject.

Fifth, the readers have different perspectives and the real-world experience. Times and times again, I was saying to myself, “Oh, I didn’t think of it this way!” Re-write!

If you want to understand the subject, write a book about it.

My co-author Anton Moiseev and I are working on the last chapter of the second edition of our Angular book, and both of us are very happy with the results. My hat off to the editors of Manning Publications for nitpicking over tiny details and finding technical errors!

The first edition of this book was recently translated into Polish, Russian, Korean, and Chinese. It’s flattering, but unfortunately, the first edition is already one year old. Too old. Besides, the foreign publisher may hire translators who are not overly familiar with the subject, and the quality of the book suffers. Reading the book in the original language is always better.

If you made it this far, I want to thank you for reading all my ramblings. Check your bookshelf, and place some orders for the latest editions of your favorite software books!

Advertisements

Always commit your yarn.lock file into the source code repo

I use the Yarn package manager for all my Angular projects. Besides being faster than npm, yarn creates a file yarn.lock that stores the exact versions of installed dependencies. Last year, I wrote about a specific use case that caused a breaking change during one of my Angular workshops.

Yesterday, I had to create a new project using Angular CLI. The project was successfully generated and started with ng serve. Then, I wanted to create a production build with ng build –prod, but the build failed with the error Cannot find module ‘uglifyjs-webpack-plugin’. I know that Webpack uses UglifyJS for optimizing sizes of the bundles, which is great, but my production build fails, which is not great at all.

The generated package.json file located in the root of my project has no direct dependency on uglifyjs-webpack-plugin, but there is one deep inside node_modules in one of the thousand (literally) dependencies used in Angular CLI projects.

To make the long story short, the WebPack team pushed to npmjs.org the new version 1.1.7 this plugin, which was empty. The Angular team got in touch with them, and an hour later, the fixed version 1.1.8 of the Webpack UglifyJS plugin was pushed to the npm central repo.

My project already had the yarn.lock file with an erroneous version of this plugin. I deleted it and ran yarn install again. This time it picked up the fixed 1.1.8 version and the ng build –prod command started working again. Thank you, the Webpack team for the quick turnaround! Happy end!

This was a specific issue with the newly generated project created at the “wrong time”. But imagine a team working on a project for some time, and their github repo didn’t include the yarn.lock file that stored the reference to the working version 1.1.6 of that plugin, and Mary (the QA engineer) decided to make a production build. A minute later, the entire team got an email titled “Who broke the build?”

The bottom line: Push the yarn.lock of the project that works and builds correctly into your version control system to ensure that the entire team has a reproducible and working build. This way, your project won’t depend on someone from across the globe submitting erroneous packages to the npmjs.org.

P.S. While npm 5 also creates the file package-lock.json with the registry of all installed dependencies, it doesn’t guarantee that each npm install will install exact versions of the packages listed there.

Creating an Angular app that weighs only 55KB

With Angular CLI, generating a new app and installing dependencies takes 30 seconds. Creating a production build takes another 15 seconds. And the best part is that the size of the deployed app can be as small as 55KB gzipped. Let’s do it.

1. Generate a minimalistic app with the inline template and styles with the following Angular CLI command:

ng new hello-world --minimal

2. If you’re not creating custom decorators and perform the AoT build, you don’t need to import the reflect polyfill, so comment out the following line in the generated file polyfills.ts:

import 'core-js/es7/reflect';

3. In the generated file app.component.ts remove most of the HTML markup from the component template so it looks as follows:

template: `Welcome to {{title}}!`

4. Make a production build (it performs the AoT compilation by default):

ng build -prod

5. The npm package serve is a small web server that can gzip static files on the fly. Install it globally:

npm install serve -g

6. Change to the dist directory where the application bundles were generated and serve the app (it’ll run on port 5000 by default):

serve .

7. Enjoy the small size!

To see it in action, watch this 5-minute video.

Update. Hello World in the upcoming rendering engine Ivy is only 3.3KB!
See https://ng-ivy-demo.firebaseapp.com/

Wrapping a RxJS observable stream into an Angular service

Angular’s dependency injection mechanism allows us to cleanly separate business logic (services) from UI (components). What if our app generates a stream of values and we want to implement it as an injectable service? In this blog, I’ll create an injectable service that emits a stream of values and a UI component subscribes to this stream displaying its values real time.

In one of my RxJS blogs  I showed you how to use the method Observable.create() providing an observer as an argument. Let’s create a service with a method that will take an observer as an argument and will emit the current time every second.

import {Observable} from 'rxjs/Observable';

export class ObservableService{

  createObservableService(): Observable<Date>{  // 1

      return new Observable(  // 2
          observer => {   // 3
              setInterval(() =>
                  observer.next(new Date())  // 4
              , 1000);
          }
      );
  }
}

1. Return an observable stream of dates
2. Create an observable
2. Provide an observer
4. Emit the new date every second

In this service, we create an instance of the RxJS Observable object, assuming that the subscriber will provide an Observer that knows what to do with the emitted data. Whenever the observable invokes the method next(new Date()) on the observer, the subscriber will receive the current date and time. Our data stream never throws an error and never completes.

We’ll inject the ObservableService into the AppComponent, which invokes the method createObservableService() and subscribes to its stream of values, creating an observer that knows what to do with the data. The observer just assigns the received time to the variable currentTime which renders the time on UI.

import 'rxjs/add/operator/map';
import {Component} from "@angular/core";
import {ObservableService} from "./observable.service";

@Component({
  selector: 'app-root',
  providers: [ ObservableService ],
  template: `<h1>Custom observable service</h1>
       Current time: {{currentTime | date: 'mediumTime'}}  // 1
  `})
export class AppComponent {

  currentTime: Date;

  constructor(private observableService: ObservableService) { // 2

    this.observableService.createObservableService()  // 3
      .subscribe( data => this.currentTime = data );  // 4
  }
}

1. Display the time using the date pipe
2. Inject the service that wraps the observable
3. Create the observable and start emitting dates
4. Subscribe to the stream of dates

This app doesn’t use any servers, and you can see it in action in the great Stackblitz online IDE  here.

In the browser’s window, the current time will be updated every second. You use DatePipe here with the format ‘mediumTime’, which displays only hours, minutes, and seconds (all date formats are described in the DatePipe documentation).

This simple example demonstrates a basic technique for wrapping any application logic in an observable stream and subscribing to it. In this case, we use setInterval(), but you could replace it with any application-specific code that generates one or more values and sends them as a stream.

Don’t forget about error handling and completing the stream if need be. The following code snippet shows a sample observable that sends one element to the observer, may throw an error and tells the observer that the streaming is complete:

return new Observable(
    observer => {
      try {
        observer.next('Hello from observable');

        //throw ("Got an error");

      } catch(err) {
         observer.error(err);
      } finally{
         observer.complete();
      }
    }
);

If you uncomment the line with a throw, observer.error() is invoked, which results in the invocation of the error handler on the subscriber if there is one.

The data producer for our observable stream was generating date/time but it could be any app code that generates some useful values, e.g. a WebSocket server generating stock quotes, auction bids, actions of online game players, etc. During my workshops, I show a sample online auction app that has a Node server emulating users’ bids on products. That server uses a WebSocket connection to push new bids for products to all users that are interested in receiving them.

Offline generation of Angular CLI projects with Yarn

There are situations when an ability to generate new Angular CLI projects from the locally installed packages is quite useful, for example:

  • You’re running a live workshop at a conference in a hotel and the students have to install project dependencies multiple times. When 20-30 people are installing Angular dependencies at the same time on a hotel’s connection, it can take three minutes or more.
  • You’re on a long flight and want to try something new with Angular.

In this post, I’ll show you how to generate Angular CLI projects in a disconnected mode.

First of all, I don’t use npm. I use Yarn for two main reasons:

  1. Yarn is faster than npm (including npm 5).
  2.  Yarn creates a file yarn.lock that keeps track of the exact version of packages installed.

For example, if package.json has a dependency “@angular/core”: “^5.0.0”, running yarn install today would include the version of 5.1.0 of this package. If you want to make sure that all devs in your team use this version even after 5.2.0 is available, push yarn.lock in the source control repo, and everyone who pulls the code will get 5.1.0. Reproducible builds are guaranteed. While npm 5 also creates a file package-lock.json, it doesn’t guarantee the same versions for all developers.

To configure Yarn as a default package manager for Angular CLI, run the following command:

ng set --global packageManager=yarn

Now let’s see how to create a local directory (a.k.a yarn offline mirror) with cached packages so Yarn can use it without the need to connect to the Internet.

Perform the following steps before boarding the plane while the Internet connection is still available.

1. Configure a directory for locally cached packages by running this command:

yarn config set yarn-offline-mirror ~/npm-packages-offline-cache

This will create a file .yarnrc in the user’s directory on your computer. In my case (I use MAC OS), this command creates the file .yarnrc with the following content

# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


lastUpdateCheck 1512857190418
yarn-offline-mirror "/Users/yfain11/npm-packages-offline-cache"

2. Generate a new project with Angular CLI without installing dependencies:

ng new hello-cli --skip-install

3. Copy the file .yarnrc into the newly generated directory hello-cli

4. Change directory to hello-cli:

cd hello-cli

5. Install the project dependencies using Yarn:

yarn install

Important: Make sure that there is no file yarn.lock in hello-cli when you run this command for the first time.

This command not only will install dependencies in the node_modules directory but will also create a directory npm-packages-offline-cache in your user’s directory. This directory will contain about a thousand of compressed package files required for the offline installation. These are gzipped files with extension .tgz. This is your Yarn offline mirror with npm packages.

6. Just in case, clear the existing yarn cache to make sure we’ll be using only the files from the mirror:

yarn cache clean

Now let’s board the plane. Turn off the wi-fi or unplug the network wire. Our aircraft is airborne.

In the hello-cli directory, run the following command:

yarn install --offline

Yarn will install all the dependencies from the offline mirror. Now you can create as many Angular CLI projects as you need without being connected:

1. Generate a new project:

ng new hello-cli2 --skip-install 

2. Copy the file .yarnrc into the hello-cli2 directory

3. Change to the project directory

cd hello-cli2

4. Run the offline installation of the project dependencies

yarn install --offline

Have a safe flight!

P.S. If you’re running a workshop, have a flash drive with the yarn offline miror directory and ask the participants to copy it into their user’s directories. Then they’d just need to run a command to create the .yarnrc file as explained in step 1.