Casual Developers Note

エンジニアやデザイナー向けの技術情報・英語学習情報・海外留学情報・海外旅行情報を提供中。世界を旅して人生を楽しもう。

  • ホーム
  • 技術 Tips & Tutorials
  • 技術塾
  • ライフハック
  • 海外留学
  • 英語学習
  • コラム
  • お問い合わせ
現在の場所:ホーム / アーカイブnodejs

2019年8月30日 By KD コメントを書く

Jenkins爆速入門: 5日間ブートキャンプ (NodeJS&Docker編)

Jenkins爆速入門: 5日間ブートキャンプ (NodeJS&Docker編)

Jenkinsに入門したいエンジニア向けにこのブログの記事の中から厳選した爆速で学べる記事を紹介します。

はじめに

JenkinsはDevOpsに欠かせない継続的インテグレーション(CI)や継続的デプロイ(CD)を実現するための専用ツールです。自前でサーバーを用意してCI/CD環境を構築する場合はこれ一択と言ってよいでしょう。この使い方を学べば、開発したアプリケーションのCI/CD環境を自分で構築できるようになります。

それでは、ブートキャンプを始めましょう。

カリキュラム

Jennkinsのインストールから基本的な使い方、メールやSlack通知、GitHubアカウント統合までを学ぶカリキュラムです。

【1日目】爆速でJenkinsをマスターしよう(NodeJS編) ~ JenkinsセットアップからNodeJS自動テスト、Job DSLまで ~

爆速でJenkinsをマスターしよう(NodeJS編) ~ JenkinsセットアップからNodeJS自動テスト、Job DSLまで ~

【2日目】爆速でJenkinsをマスターしよう(Docker編) ~ JenkinsコンテナへのDockerインストール方法からJob DSL、Jenkins Pipelineまで ~

爆速でJenkinsをマスターしよう(Docker編) ~ JenkinsコンテナへのDockerインストール方法からJob DSL、Jenkins Pipelineまで ~

【3日目】爆速でJenkinsをマスターしよう(メール通知編) ~ パイプラインのビルド失敗時にメールで通知する方法 ~

爆速でJenkinsをマスターしよう(メール通知編) ~ パイプラインのビルド失敗時にメールで通知する方法 ~

【4日目】爆速でJenkinsをマスターしよう(Slack通知編) ~ パイプラインのビルド失敗時にSlackで通知する方法 ~

爆速でJenkinsをマスターしよう(Slack通知編) ~ パイプラインのビルド失敗時にSlackで通知する方法 ~

【5日目】爆速でJenkinsをマスターしよう(GitHubアカウント統合編) ~ JenkinsのGitHub Organizationの設定方法 ~

爆速でJenkinsをマスターしよう(GitHubアカウント統合編) ~ JenkinsのGitHub Organizationの設定方法 ~

最後に

いかがでしたか?このカリキュラムを完遂したなら、Jenkinsをマスターできたに違いありません。これであなたも立派なDevOpsエンジニアの仲間入りですね!それでは。

カテゴリ : 技術塾 タグ : bootcamp, docker, jenkins, jenkins-github-organization, jenkins-job-dsl, jenkins-pipeline, nodejs

2019年6月28日 By KD コメントを書く

TypeScriptのためのバックエンド用フレームワークNestJSにさくさく入門しよう

TypeScriptのためのバックエンド用フレームワークNestJSにさくさく入門しよう

TypeScriptのためにAngularからインスパイアされて作られたバックエンド用のフレームワークNestJSについて紹介します。

はじめに

最近勢いがあるTypeScriptですが、皆さんはバックエンドのAPIを構築する場合はどんなフレームワークを使っていますか?TypeScriptを使わない時と同じようにExpressやHapiなどを使っている人が多いと思いますが、もう一つ新しい選択肢があります。それはNestJSです。特徴は、Angularのようにバックエンドを書ける点と、結果としてフォルダやファイルの構成が明確化されているので、構成に悩むことなく本来のAPI開発に専念できる点です。

今回はNestJSで簡単なCRUDのAPIをさくさく作ってみましょう。

NestJSとは?

NestJSとは、TypeScriptおよびモダンJavaScriptのために作られたエンタープライズ級のNodeJSフレームワークです。冒頭でも述べたとおり、Angularにインスパイアされているため、Angularのような書き方でコーディングすることができます。(デコレータを使ったコーディングですね。)フォルダやファイルの構成も分かりやすく、フレームワークとして必要な機能もしっかりと有しています。ドキュメントもしっかり書かれており、サンプルとなるソースコードも公開されているので、すぐに開発が始められます。

簡単なAPIを作ってみよう

それでは、今回はユーザを管理する簡単なAPIを作ってみましょう。

ベースを作る

NestCLIコマンドを使ってプロジェクトを生成し、必要なフォルダとファイルを作成します。

$ yarn add glbal @nestjs/cli
$ nest --version
6.5.0
$ nest new my-nestjs-api
...
? Which package manager would you ❤️  to use? yarn
...
$ cd my-nestjs-api/
$ yarn add uuid @types/uuid joi @types/joi
$ mkdir -p src/common/pipes
$ mkdir -p src/users
$ mkdir -p src/users/models
$ mkdir -p src/users/dto
$ mkdir -p src/users/schemas
$ touch src/common/pipes/validation.pipe.ts
$ touch src/users/users.service.ts
$ touch src/users/users.controller.ts
$ touch src/users/users.module.ts
$ touch src/users/models/user.model.ts
$ touch src/users/schemas/create-user.schema.ts
$ touch src/users/schemas/update-user.schema.ts
$ touch src/users/schemas/user.enum.ts
$ touch src/users/users.controller.spec.ts
$ rm src/app.service.ts 
$ rm src/app.controller.ts 
$ rm src/app.controller.spec.ts
$ tree src/
src/
├── app.module.ts
├── common
│   └── pipes
│       └── validation.pipe.ts
├── main.ts
└── users
    ├── dto
    │   ├── create-user.dto.ts
    │   └── update-user.dto.ts
    ├── models
    │   └── user.model.ts
    ├── schemas
    │   ├── create-user.schema.ts
    │   ├── update-user.schema.ts
    │   └── user.enum.ts
    ├── users.controller.spec.ts
    ├── users.controller.ts
    ├── users.module.ts
    └── users.service.ts

構成ができました。

ユーザをCRUDするAPIを作る

ユーザを管理するCRUDのAPIを実装しましょう。

create-user.dto.ts

export class CreateUserDto {
  readonly name: string;
  readonly gender: string;
  readonly age: number;
}

update-user.dto.ts

export class UpdateUserDto {
  readonly name: string;
  readonly gender: string;
  readonly age: number;
}

user.model.ts

export class User {
  constructor(
    public id: string,
    public name: string,
    public gender: string,
    public age: number,
  ) {}
}

users.service.ts

import { Injectable, NotFoundException } from '@nestjs/common';
import { v4 as uuid } from 'uuid';
import { User } from './models/user.model';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';

@Injectable()
export class UserService {
  private users: User[] = [];

  createUser(createUserDto: CreateUserDto) {
    const userId = uuid();
    const newUser = new User(
      userId,
      createUserDto.name,
      createUserDto.gender,
      createUserDto.age,
    );
    this.users.push(newUser);
    return userId;
  }

  readAllUsers() {
    return [...this.users];
  }

  readUser(userId: string) {
    const [user, _] = this.findUser(userId);
    return { ...user };
  }

  updateUser(userId: string, updateUserDto: UpdateUserDto) {
    const [user, index] = this.findUser(userId);
    const updateUser = { ...user };
    if (updateUserDto.name) {
      updateUser.name = updateUserDto.name;
    }
    if (updateUserDto.gender) {
      updateUser.gender = updateUserDto.gender;
    }
    if (updateUserDto.age) {
      updateUser.age = updateUserDto.age;
    }
    this.users[index] = { ...updateUser };
  }

  deleteUser(userId: string) {
    const [user, _] = this.findUser(userId);
    this.users = this.users.filter(u => u.id !== user.id);
  }

  private findUser(id: string): [User, number] {
    const index = this.users.findIndex(u => u.id === id);
    const user = this.users[index];
    if (!user) {
      throw new NotFoundException(`Could not find the user of id: ${id}`);
    }
    return [user, index];
  }
}

users.controller.ts

import {
  Body,
  Controller,
  Get,
  Post,
  UsePipes,
  Param,
  Patch,
  Delete,
} from '@nestjs/common';
import { UserService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';

@Controller('users')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Post()
  addUser(@Body() createUserDto: CreateUserDto) {
    const userId = this.userService.createUser(createUserDto);
    return {
      id: userId,
    };
  }

  @Get()
  getAllUsers() {
    return this.userService.readAllUsers();
  }

  @Get(':id')
  getUser(@Param('id') id: string) {
    return this.userService.readUser(id);
  }

  @Patch(':id')
  updateUser(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
    this.userService.updateUser(id, updateUserDto);
    return null;
  }

  @Delete(':id')
  removeUser(@Param('id') id: string) {
    this.userService.deleteUser(id);
    return null;
  }
}

users.module.ts

import { Module } from '@nestjs/common';
import { UserController } from './users.controller';
import { UserService } from './users.service';

@Module({
  controllers: [UserController],
  providers: [UserService],
})
export class UserModule {}

app.module.ts

import { Module } from '@nestjs/common';
import { UserModule } from './users/users.module';

@Module({
  imports: [UserModule],
  controllers: [],
  providers: [],
})
export class AppModule {}

main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}
bootstrap();

一通り完成しました。

バリデーションを追加する

PipeにJoiでのバリデーションを追加しましょう。

user.enum.ts

export enum Gender {
  Male = 'male',
  Female = 'female',
}

create-user.schema.ts

import * as Joi from 'joi';
import { Gender } from './user.enum';

export const createUserSchema = Joi.object().keys({
  name: Joi.string()
    .min(3)
    .required(),
  gender: Joi.string()
    .valid([Gender.Male, Gender.Female])
    .required(),
  age: Joi.number()
    .integer()
    .min(0)
    .required(),
});

update-user.schema.ts

import * as Joi from 'joi';
import { Gender } from './user.enum';

export const updateUserSchema = Joi.object().keys({
  name: Joi.string().min(3),
  gender: Joi.string().valid([Gender.Male, Gender.Female]),
  age: Joi.number()
    .integer()
    .min(0),
});

validation.pipe.ts

import * as Joi from 'joi';
import {
  PipeTransform,
  Injectable,
  ArgumentMetadata,
  BadRequestException,
} from '@nestjs/common';

@Injectable()
export class ValidationPipe implements PipeTransform {
  constructor(private readonly schema: Object) {}

  transform(value: any, metadata: ArgumentMetadata) {
    const { error } = Joi.validate(value, this.schema);
    if (error) {
      throw new BadRequestException(error);
    }
    return value;
  }
}

users.controller.ts (追記)

import {
  Body,
  Controller,
  Get,
  Post,
  UsePipes,
  Param,
  Patch,
  Delete,
} from '@nestjs/common';
import { UserService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { ValidationPipe } from '../common/pipes/validation.pipe';
import { createUserSchema } from './schemas/create-user.schema';
import { updateUserSchema } from './schemas/update-user.schema';

@Controller('users')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Post()
  @UsePipes(new ValidationPipe(createUserSchema))
  addUser(@Body() createUserDto: CreateUserDto) {
    const userId = this.userService.createUser(createUserDto);
    return {
      id: userId,
    };
  }

  @Get()
  getAllUsers() {
    return this.userService.readAllUsers();
  }

  @Get(':id')
  getUser(@Param('id') id: string) {
    return this.userService.readUser(id);
  }

  @Patch(':id')
  @UsePipes(new ValidationPipe(updateUserSchema))
  updateUser(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
    this.userService.updateUser(id, updateUserDto);
    return null;
  }

  @Delete(':id')
  removeUser(@Param('id') id: string) {
    this.userService.deleteUser(id);
    return null;
  }
}

これでバリデーションの追加ができました。

少しテストを書いてみる

最後に、コントローラーのテストを少し書いて動作確認しましょう。

users.controller.spec.ts

import { Test, TestingModule } from '@nestjs/testing';
import { UserController } from './users.controller';
import { CreateUserDto } from './dto/create-user.dto';
import { Gender } from './schemas/user.enum';
import { UserService } from './users.service';
import { UpdateUserDto } from './dto/update-user.dto';
import { NotFoundException } from '@nestjs/common';
describe('UserController', () => {
let userController: UserController;
beforeEach(async () => {
const app: TestingModule = await Test.createTestingModule({
controllers: [UserController],
providers: [UserService],
}).compile();
userController = app.get<UserController>(UserController);
});
describe('addUser', () => {
it('should return id of the new user', () => {
const newUser: CreateUserDto = {
name: 'Tom',
gender: Gender.Male,
age: 22,
};
expect(userController.addUser(newUser)).toHaveProperty('id');
});
});
describe('getAllUsers', () => {
it('should return all users', () => {
const users: CreateUserDto[] = [
{
name: 'Tom',
gender: Gender.Male,
age: 22,
},
{
name: 'Mary',
gender: Gender.Female,
age: 19,
},
{
name: 'Keid',
gender: Gender.Male,
age: 30,
},
];
userController.addUser(users[0]);
userController.addUser(users[1]);
userController.addUser(users[2]);
expect(userController.getAllUsers()).toEqual(
users.map(user => ({ ...user, id: expect.anything() })),
);
});
});
describe('getUser', () => {
it('should return a user', () => {
const users: CreateUserDto[] = [
{
name: 'Tom',
gender: Gender.Male,
age: 22,
},
{
name: 'Mary',
gender: Gender.Female,
age: 19,
},
{
name: 'Keid',
gender: Gender.Male,
age: 30,
},
];
const userId0 = userController.addUser(users[0]).id;
const userId1 = userController.addUser(users[1]).id;
const userId2 = userController.addUser(users[2]).id;
expect(userController.getUser(userId0)).toEqual({
...users[0],
id: userId0,
});
expect(userController.getUser(userId1)).toEqual({
...users[1],
id: userId1,
});
expect(userController.getUser(userId2)).toEqual({
...users[2],
id: userId2,
});
});
});
describe('updateUser', () => {
it('should update the user', () => {
const newUser: CreateUserDto = {
name: 'Mary',
gender: Gender.Female,
age: 19,
};
const addedUserId = userController.addUser(newUser).id;
const updateUser: UpdateUserDto = {
name: 'Super Man',
gender: Gender.Male,
age: 100,
};
userController.updateUser(addedUserId, updateUser);
expect(userController.getUser(addedUserId)).toEqual({
...updateUser,
id: addedUserId,
});
});
});
describe('removeUser', () => {
it('should remove the user', () => {
const users: CreateUserDto[] = [
{
name: 'Keid',
gender: Gender.Male,
age: 30,
},
{
name: 'Jobs',
gender: Gender.Male,
age: 56,
},
];
const userId0 = userController.addUser(users[0]).id;
const userId1 = userController.addUser(users[1]).id;
userController.removeUser(userId1);
expect(userController.getAllUsers()).toHaveLength(1);
expect(() => userController.getUser(userId1)).toThrow();
});
});
});

テストを実行してみましょう。

$ yarn test
...
PASS  src/users/users.controller.spec.ts
UserController
addUser
✓ should return id of the new user (11ms)
getAllUsers
✓ should return all users (4ms)
getUser
✓ should return a user (2ms)
updateUser
✓ should update the user (2ms)
removeUser
✓ should remove the user (2ms)
Test Suites: 1 passed, 1 total
Tests:       5 passed, 5 total
Snapshots:   0 total
Time:        2.743s, estimated 3s
Ran all test suites.
✨  Done in 3.83s.

OKですね。

最後に

いかがでしたか?これでNestJSの基本はマスターできたと思います。ルールが決まっているので簡単に実装が始められるところが良いですね。ちなみに、現在NestJSのGitHubページ上に日本語のドキュメントが無いので、コントリビュートするチャンスですよ(笑)それでは。

環境

  • NodeJS: v12.3.1
  • Yarn: 1.16.0
  • TypeScript: 3.5.2
  • NestJS: 6.5.0

カテゴリ : 技術 Tips & Tutorials タグ : nestjs, nodejs, rest-api, typescript

2019年5月20日 By KD コメントを書く

DockerコンテナのThe PID 1 Problemとその解決策(NodeJS編)

DockerコンテナのThe PID 1 Problemとその解決策(NodeJS編)

Dockerでアプリケーションを構築する場合に発生するメジャーな問題である「The PID 1 Problem」とその解決策を紹介します。

はじめに

アプリケーションをDocker化するにあたり、プロダクション用のDockerfileでは開発用のDockerfile以上にいくつか気をつける点があります。その中の一つが今回紹介する「The PID 1 Problem」の対応です。Dockerをプロダクションに適用する場合は、理解しておく必要があります。それでは、問題の内容と解決策を見ていきましょう。

The PID 1 Problemとは?

「The PID 1 Problem」とは、この記事で指摘されているDockerコンテナのPID 1に関する問題です。一般的にPID 1は「initプロセス」と呼ばれており、システムが起動した際に最初に起動するプロセスです。このinitプロセスの役割は、ゾンビプロセスの除去とサブプロセスへのシグナルの伝搬です。何の対策もせずにアプリケーションをDocker上で起動した場合、そのアプリケーションの起動プロセスがコンテナ上の最初のプロセスになってしまうため、ゾンビプロセスが残ったり、シグナルが正しく処理されないという問題が発生します。開発者として明確に困る点は、Docker化したアプリケーションが正しく停止しないことです。

tiniとは?

「tini」とは、コンテナ向けに作られたシンプルなinitプログラムです。Dockerコンテナの起動コマンドで使用することで、PID 1の本来の役割を果たし、「The PID 1 Problem」を回避できます。

解決策

それではNodeJSの簡単なDockerアプリケーションを作って、「The PID 1 Problem」を解決してみましょう。

サンプルNodeJSアプリケーションの作成

単にメッセージを返すだけのアプリケーションを作ります。

$ mkdir dockerized-app-fixed-pid1
$ cd dockerized-app-fixed-pid1/
$ yarn init -y
$ yarn add express
$ touch app.js
$ touch Dockerfile
$ touch .dockerignore

コードは以下のようにします。

app.js

const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hey, dockerized app!');
});
app.listen(3000, () => {
console.log('Dockerized app is up...');
});

Dockerfile

FROM node:12.2-alpine
ENV NODE_ENV=production
WORKDIR /node
COPY package.json yarn.lock ./
RUN mkdir app && chown -R node:node .
USER node
RUN yarn install && yarn cache clean --force
WORKDIR /node/app
COPY --chown=node:node . .
EXPOSE 3000
CMD ["node", "app.js"]

.dockerignore

node_modules/

試しにビルドして実行してみましょう。

$ docker build -t dockerized-app .
$ docker run -p 3000:3000 dockerized-app
Dockerized app is up...

動作確認してから停止します。

$ curl localhost:3000/
Hey, dockerized app!
$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS                    NAMES
a3b8c29a79c6        dockerized-app      "node app.js"       About a minute ago   Up 59 seconds       0.0.0.0:3000->3000/tcp   quizzical_heyrovsky
$ docker top a3b
PID                 USER                TIME                COMMAND
55419               1000                0:00                node app.js
$ docker stop a3b
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS                       PORTS               NAMES
a3b8c29a79c6        dockerized-app      "node app.js"       About a minute ago   Exited (137) 4 seconds ago                       quizzical_heyrovsky
$ docker rm a3b

注目点として、このコンテナはControl+Cやdocker stopで停止しようとしてもすぐに停止することはなく、正しい停止処理で失敗して強制終了する形で停止しています。

補足として、NodeJSにおけるExit Codeの見方ですが、公式サイトのExit Codeのページを見ると書かれています。つまり、NodeJSのSignal ExitはUnixのSignal Numberに128を足した数字になります。上記の場合は、Exit Codeは「137」なので、128+9ということであり、「9」は「SIGKILL」のシグナルを示しているので、強制終了されていることが分かります。

--initによる対応(一時的な起動)

Dockerの「--init」オプションと使うことでDockerに同封されているinitプロセスを有効にできます。開発環境など一時的にこの問題を解決したい場合に適しています。

それではこのオプションを付けて起動します。

$ docker run --init -p 3000:3000 dockerized-app
Dockerized app is up...

停止します。

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAM
ES
200687bc9992        dockerized-app      "node app.js"       38 seconds ago      Up 37 seconds       0.0.0.0:3000->3000/tcp   vig
ilant_hofstadter
$ docker top 200
PID                 USER                TIME                COMMAND
55642               1000                0:00                /dev/init -- node app.js
55677               1000                0:00                node app.js
$ docker stop 200
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                       PORTS               NAMES
200687bc9992        dockerized-app      "node app.js"       54 seconds ago      Exited (143) 7 seconds ago                       vigilant_hofstadter
$ docker rm 200

停止はすばやく実行され、Exit Code「143」(128+15なので「SIGTERM」)で正常に終了しています。

tiniによる対応(永続的な起動)

「tini」をDockerfile上に追加することでプロダクション用にこの問題を解決できます。今回はtiniの「-e」オプションを使い、Exit Code「143」を「0」にマップすることにします。

Dockerfile

FROM node:12.2-alpine
ENV NODE_ENV=production
RUN apk add --no-cache tini
WORKDIR /node
COPY package.json yarn.lock ./
RUN mkdir app && chown -R node:node .
USER node
RUN yarn install && yarn cache clean --force
WORKDIR /node/app
COPY --chown=node:node . .
EXPOSE 3000
ENTRYPOINT ["/sbin/tini", "-e", "143", "--"]
CMD ["node", "app.js"]

それでは変更したDockerfileでビルドして起動します。

$ docker build -t dockerized-app .
$ docker run -p 3000:3000 dockerized-app
Dockerized app is up...

停止します。

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  
NAMES
c7ebb0d93ce7        dockerized-app      "/sbin/tini -e 143 -…"   10 seconds ago      Up 9 seconds        0.0.0.0:3000->3000/tcp 
cocky_haslett
$ docker top c7e
PID                 USER                TIME                COMMAND
55904               1000                0:00                /sbin/tini -e 143 -- node app.js
55938               1000                0:00                node app.js
$ docker stop c7e
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS               NAMES
c7ebb0d93ce7        dockerized-app      "/sbin/tini -e 143 -…"   36 seconds ago      Exited (0) 5 seconds ago                       cocky_haslett

Exit Code「0」で想定通りに終了しています。

最後に

いかがでしたか?これでDockerコンテナのメジャーな問題である「The PID 1 Problem」を解決できるようになったと思います。プロダクションでDockerを適用する際は注意しましょう。それでは。

環境

  • Docker: 18.09.2
  • NodeJS: v12.2.0
  • Yarn: 1.16.0

カテゴリ : 技術 Tips & Tutorials タグ : docker, nodejs

  • 1
  • 2
  • 3
  • …
  • 5
  • 次のページ »

ブログ更新情報や海外の関連情報などを配信する無料メルマガ

Sponsored Links

About Author

KD

世界を旅し日本を愛するエンジニア。大学でコンピュータサイエンスの楽しさを学び、日本の大手IT企業で働く中で、新しい技術やスケールするビジネスが北米にある事に気づく。世界に挑戦するための最大の壁が英語であったため、フィリピン留学およびカナダ留学を経て英語を上達させた。現在は日本在住でエンジニアとして働きつつ、次の挑戦に備えて世界の動向を注視している。挑戦に終わりはない。このブログでは、エンジニアやデザイナー向けの技術情報から、海外に留学したい人向けの留学情報、海外に興味がある人向けの海外旅行情報など、有益な情報を提供しています。

https://casualdevelopers.com/

最近の投稿

  • 2020年JS周辺のバックエンド寄りの注目技術!ネクストNodeJSの「Deno」と分散型パッケージレジストリの「Entropic」の紹介

    2020年JS周辺のバックエンド寄りの注目技術!ネクストNodeJSの「Deno」と分散型パッケージレジストリの「Entropic」の紹介

    2020年1月13日
  • 今さら聞けないJavaによる関数型プログラミング入門 ~ラムダ式、ストリーム、関数型インターフェース~

    今さら聞けないJavaによる関数型プログラミング入門 ~ラムダ式、ストリーム、関数型インターフェース~

    2019年11月4日
  • ReactのためのEslintおよびPrettierの設定方法 ~Airbnb JavaScript Style Guideの適用~

    ReactのためのEslintおよびPrettierの設定方法 ~Airbnb JavaScript Style Guideの適用~

    2019年10月30日
  • BashからZshに移行する方法(Mac編)

    BashからZshに移行する方法(Mac編)

    2019年10月21日
  • Create React Appを使わないでゼロからReactの開発環境を構築する方法(Webpack/Docker編)

    Create React Appを使わないでゼロからReactの開発環境を構築する方法(Webpack/Docker編)

    2019年9月30日

カテゴリ

  • 技術 Tips & Tutorials (100)
  • 技術塾 (6)
  • ライフハック (26)
  • 海外留学 (12)
  • 英語学習 (3)
  • コラム (6)

アーカイブ

最高の学習のために

人気記事ランキング

  • MySQLで「ERROR 2003 (HY000): Can't connect to MySQL server」と怒られた時の対処法
    MySQLで「ERROR 2003 (HY000): Can't connect to MySQL server」と怒られた時の対処法
  • Jupyter Notebookで「The kernel appears to have died. It will restart automatically.」というエラーが出た場合の原因と対処法
    Jupyter Notebookで「The kernel appears to have died. It will restart automatically.」というエラーが出た場合の原因と対処法
  • 爆速でJenkinsをマスターしよう(GitHubアカウント統合編) ~ JenkinsのGitHub Organizationの設定方法 ~
    爆速でJenkinsをマスターしよう(GitHubアカウント統合編) ~ JenkinsのGitHub Organizationの設定方法 ~
  • Expressで「Cannot set headers after they are sent to the client」と怒られた時の対処法
    Expressで「Cannot set headers after they are sent to the client」と怒られた時の対処法
  • SAKURAのメールボックスで独自ドメインのメールを設定し、Gmail経由で送受信する方法
    SAKURAのメールボックスで独自ドメインのメールを設定し、Gmail経由で送受信する方法
  • バンクーバー留学豆知識:バンクーバーのATMで日本の銀行のキャッシュカードを使ってお得にお金を引き出す方法
    バンクーバー留学豆知識:バンクーバーのATMで日本の銀行のキャッシュカードを使ってお得にお金を引き出す方法
  • [tips][perl] Perlで文字コードをいい感じに処理する方法
    [tips][perl] Perlで文字コードをいい感じに処理する方法
  • PythonでWebスクレイピング入門(Scrapy+Selenium編)
    PythonでWebスクレイピング入門(Scrapy+Selenium編)
  • Amazon EC2インスタンスにSSHできなくなった時の対処法
    Amazon EC2インスタンスにSSHできなくなった時の対処法
  • SpringBootのProfile毎にプロパティを使い分ける3つの方法
    SpringBootのProfile毎にプロパティを使い分ける3つの方法

Bitcoin寄付 / BTC Donation

Bitcoinを寄付しよう

BTC
Select Payment Method
Personal Info

Donation Total: BTC 0.0010

このブログの運営のためにBitcoinでの寄付を募集しています。お気持ち程度の寄付を頂けると管理者の励みになります。

Bitcoin寄付について知りたい方はこちらの記事へ

ビットコイン取引ならここ

  • ホーム
  • 技術 Tips & Tutorials
  • 技術塾
  • ライフハック
  • 海外留学
  • 英語学習
  • コラム
  • サイトマップ
  • タグ一覧
  • プライバシーポリシー
  • お問い合わせ

Copyright © 2023 KD - Casual Developers Notes