ナガモト の blog

Full Cycle Developerを目指すエンジニアが有用そうな技術記事や、ポエムのようなよしなしごとを投稿するブログです。

「マンガでやさしくわかるアンガーマネジメント」を読みました

感情的になることと、感情を伝えることはイコールではありません。

私が「マンガでやさしくわかるアンガーマネジメント」から得た最も重要なセンテンスです。

マンガでやさしくわかるアンガーマネジメント

マンガでやさしくわかるアンガーマネジメント

本書を読んだ経緯

本書はマンガでわかる〜シリーズがセールだったときにたくさん衝動買いしたうちの1冊です。しばらくは積ん読状態でした。

読み始めたきっかけは次の記事です。 kdnakt.hatenablog.com この記事がアンガーマネジメントを簡単にでもすぐに学んだ方がいいと私に思わせてくれました。

概要

タイトルから察する通り、怒りという感情とうまく付き合うためのノウハウやトレーニングをマンガ付きで説明するという内容になっています。小難しい専門的な話を詳細に説明するのではなく、ノウハウやTipsを明日から活かせるように噛み砕いて解説しています。文量は少なく、速読でなくとも2, 3時間で読めてしまうでしょう。これはよくまとまっているということであり、長所です。

早速活かしたいノウハウとTips

一部抜粋して紹介します。

怒りのピーク6秒をやり過ごすテクニック

怒りの現場から席を外し頭を冷やすというタイムアウト。深い腹式呼吸を意識する呼吸リラグゼーション。これらは場所を選ばずシンプルで実行しやすく、実際にやってみても効果的でした。アンガーマネジメントという言葉を知らなくてもやってる人はいると思います。

アンガーログ

どういう時に怒りを感じているのかを自覚するために怒りを感じた時に何を思ったかを記録します。実際にやってみると、怒っているときに自分は怒っていると冷静になれるところも良いです。

「べき」ログ

怒りの元を知るための「べき」を記録します。私の簡単な例としては「電車では降車が終わる前に乗り込むべきではない」という「べき」が記録されました。やり始めると、守って当然のマナーをたくさんの「べき」として記録することになりました。しかし、どれも自分が変えることのできない他人のマナー違反であり、それを怒って気分を悪くするのは生産的ではないと再認識できました。

特に響いた表現と所感

がまんではなく、〝見極めた〟と考える

怒ってもいいことを我慢してやった。自分ばかり我慢している。と溜め込んでしまうことがあります。これからはそうではなく、「怒っても事態は好転しないと見極め、怒らないことを選択した」と考えるようにしたいです。

相手を打ち負かそうとせず、わかってもらうことをゴールにする

論理的に正しいことを言い、相手を論破してしまうことがあります。打ち負かそうとした場合、論破できなければそもそも怒りは治りませんし、論破できてもわかってもらえるわけではないため、事あるごとに衝突してしまうでしょう。名著「人を動かす」*1でも「議論に勝つ最善の方法は議論を避ける事だ」といった主旨のことが書いてありましたし、論破に意味はないことを再度心に刻みました。

最後に

感情に流されず、怒りと上手に付き合えれば色んなことが少しずつやりやすくなると思います。本書には紹介したもの以外にも明日から試せる簡単なノウハウ・Tipsがたくさん詰まっています。怒りっぽかったり、溜め込んでしまう人にはおすすめです。さっと読めてしまう文量でもあるので、騙されたと思ってどうぞ。

マンガでやさしくわかるアンガーマネジメント

マンガでやさしくわかるアンガーマネジメント

*1:

人を動かす 文庫版

人を動かす 文庫版

エンジニアなので家系図をGitHub上にYAML形式で管理する

あなたは親戚の名前や兄妹の人数など覚えているでしょうか?私は覚えられません。まして結婚して親戚の数が倍になると言うまでもないです。また、先日の母とこのような会話をしました。

母「aさん(私の嫁の叔母)って bさん(私の嫁の父)の姉なの?妹なの?」

私「aさんはbさんの姉だよ。」

私は思いました。

これ前も聞かれなかったか?

というか、誰かが結婚する度に親戚が増えるわけだから覚えられるわけなくね?

ということで情報共有とその可視化に取り組むことにしました。

技術選定

  • 管理・更新が容易(テキストベース)
  • 図を自動生成できる

上記の条件を満たすOSSがありました。*1 github.com

kingraphとは

家系図JavaScriptGraphvizで作図するツールです。インストール方法などはREADMEをみましょう。

以下ではドラゴンボール家系図を例に書き方を軽く説明します。

例: ドラゴンボール孫悟空周りの家系図

https://github.com/nagamoto/db-family-tree/blob/master/son.png?raw=true

牛魔王やサタンの妻はわからないのでとりあえず”牛魔王の妻”・”サタンの妻”としています

YAMLファイルの書き方

ソース: db-family-tree/son.yml at master · nagamoto/db-family-tree · GitHub

親子は次のように定義できます。簡単ですね。

parents: [悟空, チチ]
children: [悟飯, 悟天]

それぞれの人の詳細を設定することもできます。今回は兄弟の生まれた順番を図に表現するために、fullnameというプロパティを本来とは違う用途で利用しています。また、後述するスタイリングのためにclassにmaleを指定しています。

people:
  ラディッツ:
    fullname: 第一子
    class: [male]
  悟空:
    fullname: 第二子
    class: [male]

図に細かなスタイリングを施すこともできます。今回は男性であれば枠が青、女性であれば枠が赤となるように設定しました。

styles:
  male:
    color: blue
  female:
    color: red

保守運用

誰かが結婚したり、子供が生まれたりしたときにはPullRequestを投げてもらいます。*2これでエンジニアらしく、常に最新の家系図が作成されます。

最後に

マジレスをすると、そもそも結婚や出産はそう頻繁に起こることではないので、これはやりすぎです。 また、「親族にエンジニアはそう何人もいない」=「メンテナが少ない」となるため、特定の少数メンバのみが更新するというつらい運用になるでしょう。

*1:最初はPlantUMLでクラス図の記法で家系図を書こうとしていましたが、兄妹をうまく表現できず諦めました

*2:太郎くんが生まれた際に作られるブランチはdeploy-taroでしょうか

最も汎用的なパターン「完全コンストラクタ(Complete Constructor)パターン」の紹介

好きなパターンはなんですか?と聞かれたら私が真っ先に答えるのは「完全コンストラクタ(Complete Constructor)パターン」です。汎用的かつ効果的なパターンなので、多くの人に知ってもらいたくて記事を書きました。

「完全コンストラクタ(Complete Constructor)パターン」とは?

コンストラクタですべてのプロパティ(メンバ変数)を設定し終える(完全な状態)を作るパターンです。setterは作らず、プロパティがコンストラクタの実行後に変わることはありません。

簡単な例

四則演算を行うCalculatorClassをRubyで書くと次のようになります。*1プロパティをinitilizeで設定した後は一切変更していません。

class Calculator
  attr_reader :operand1, :operand2

  def initialize(operand1:, operand2:)
    @operand1 = operand1; @operand2 = operand2
  end

  def sum
    operand1 + operand2
  end

  def difference
    operand1 - operand2
  end

  def product
    operand1 * operand2
  end

  def quotient
    operand1 / operand2
  end
end

※attr_readerはgetterメソッドのようなものをまとめて定義してくれると思ってください。詳しくはこちら

長所

  • 可読性が高まる
  • 単一責任原則(SRP)を守りやすい

可読性が高まる理由

完全コンストラクタに則ったクラスはその性質上、IF(インターフェース)がシンプルになりクラス内の見通しがよくなります。また、クラスを呼び出す側においても、プロパティをまとめて入力してインスタンス化し、目的のメソッドを実行するというシンプルな流れになります。そこかしこでsetterが呼ばれ、状態が変わることがないため非常に見通しがよくなります。

ccc = CompleteConstructorClass.new(x, y, z) 
ccc.do

単一責任原則(SRP)を守りやすい理由

操作に必要なプロパティすべてをまとめて入力するため、多種多様な責務をクラスに持たせることが難しいです。*2また、インスタンス化後にプロパティを変更できないため、メソッド実行結果は(基本的に)同じ結果を返します。そのためメソッド実行後にインスタンスを使い捨てることが多く、使い回して多数の責務を持つような実装にはしづらくなります。一度インスタンス化してしまえば、メソッド実行結果は同じものを返すため、テストも非常に行いやすいです。

具体例: Finderパターンを完全コンストラクタで実装

Railsで構築されたあるSNSアプリで、ユーザは氏名・生年月日・性別・出生都道府県・現住都道府県のような情報を持つ。そのアプリでユーザを複雑な条件で絞り込みたいときに(Finderパターン)を使うとして、それを完全コンストラクタで実装します。

class UserFinder
  attr_reader :gender, :age, :today, :born_in_prefecture, :living_in_prefecture

  def initialize(gender: nil, age: nil, born_in_prefecture: nil, living_in_prefecture: nil)
    @gender = gender; @age = age; @today = Date.current
    @born_in_prefecture = born_in_prefecture; @living_in_prefecture = living_in_prefecture
  end

  def find
    query = User.all
    query = query.where(gender: gender) if gender
    query = query.where(born_in_prefecture: born_in_prefecture) if born_in_prefecture
    query = query.where(born_in_prefecture: living_in_prefecture) if living_in_prefecture
    query = query.where(birth_day: period_covered) if age

    return query
  end

  private

    def period_covered
      from_date = today - (age + 1).year + 1.day
      to_date = today - age
      from_date..to_date
    end
end

このように検索の実装部分が多少複雑でも、利用時は次のとおりで「大阪生まれで今東京に住んでいる20才」を検索するということが一目瞭然になります。

result = UserFinder.new(age: 20, born_in_prefecture: "大阪", living_in_prefecture: "東京").find

Finderパターン以外にのデザインパターンとも相性がよく組み合わせて使用することでよりよい設計ができるようになります。

総括

「完全コンストラクタ(Complete Constructor)パターン」はシンプルなパターンで覚えやすいのに、汎用的かつ効果的なのでぜひ利用してください!

おまけ: デザインパターンに関する参考資料

オブジェクト指向における再利用のためのデザインパターン

オブジェクト指向における再利用のためのデザインパターン

www.techscore.com masato-hi.hatenablog.jp

*1:Mathモジュール使えとか野暮なことは言わないでください

*2:多種多様な責務を果たすにはインスタンス化する際に大量のプロパティをまとめて入力しなければならないため

2019年2月振り返り

もう2月が終わりました。ということで振り返りをやっていきます。

振り返りの手法はびば(森のフレンズ)/技術書典6 お34 ふりかえり読本 学び編 (@viva_tweet_x) | Twitterさんが行なっているYWTを参考にしています。*1

Y: やったこと

メンティーを卒業しました。アウトプットする習慣を身につけることができて本当に良かったと思います。

2月は技術系のアウトプットを出すことを目標にしていました。目標としていた量については達成することができました。ただし、まだまだ質は伴っていないと感じるのでインプットもアウトプットも継続していきます。

1月振り返りでの宣言のうちやれなかったこと(やれたことは打ち消し線)

  • ブログメンティー継続しつつも2月末に自走できる状態にし、胸を張って卒業
  • ブログ週2記事(うち1記事は技術ネタ)投稿
  • 既読本を読み直し、読書エントリを書く
  • 学習・アウトプットをKanbanFlowで管理し、取り組む
  • 技術系LTをする
  • フィットネスバイクと筋トレを継続し、3kg減量する

読書エントリについては忘れていました。技術記事を書くことを目標としていたので、未達なのは大きな問題ではないです。ただし宣言していたことを忘れてしまうのは振り返りの意味がなくなってしまうので反省が必要そうです。

減量を達成できなかった理由は、カフェに勉強に行くことが増え、そこで余計なカロリーを摂取したためです。一時期は少しリバウンドまでしていたため、-1kgできているだけまだ良かったとは思います。*5運動は1日も欠かさずやることができたのでよかったです。

W: わかったこと

  • 技術系の記事に感じるハードルは自分が勝手に設定しているもの
  • とはいえ記事の質はPVに如実に出る
  • 赤ちゃんがおきている昼間にポモドーロを回すのは難しい
  • 文章について体系的に学ぶ必要がある
  • 文章を書く実践も続ける必要がある
  • ブログにおいても「Done is better than perfect.」

https://pbs.twimg.com/media/Ck9_MOJWYAAR_Rm.jpg

T: つぎ(3月)にやること

  • 育児・自主学習・仕事のリズムを作る(3月から復職のため)
  • RailsDMに参加し、レポートを書く
  • 週1記事以上投稿
  • 技術系で2記事以上投稿
  • 「アンガーマネジメント」の読書エントリを書く
  • 文章力向上のための本を1冊読む
  • 学習・アウトプットをKanbanFlowで管理し、取り組む)(継続)
  • 2kg減量する

3月から復職するため生活リズムが大きく変わります。その中でもリズムを整え、コンスタントに自主学習をやっていける状態にもっていくことが最重要課題です。

また、文章力に課題があるため本で体系的に学びます。

その他雑感

子供が可愛いので働きもせず家でいちゃいちゃしていたいです。仕事にも精がでます。

*1:twitter.com

*2:2月後半は2記事とも技術記事という縛りも追加しました

*3:ngmt83.hatenablog.com

*4:chrome.google.com

*5:最近ブラックコーヒーのみの注文で居座る強心臓を獲得しました

Node.js環境のクリーンアップとfnmの再導入

ngmt83.hatenablog.com に記載した対策「Node.js環境のクリーンアップとfnmの再導入」の手順を記事に残しておきます。

前提

  • グローバルにNode.jsがインストール済み
  • Node.jsのバージョン管理ツールを導入したことがある(n, nvm, nodebrew, fnmなど)
  • グローバルのものとバージョン管理ツール経由のものと混在し、いくらか問題が発生している

そのため、Node.jsをすべてアンインストールし、fnm経由で再インストールします。

概要

  • グローバルのNode.jsのアンインストール
  • Node.jsバージョン管理ツールのアンインストール
  • fnmのインストール

グローバルのNode.jsのアンインストール

次のコマンドでグローバルのNode.jsをアンインストールしました。

> rm -rf /usr/local/lib/node
> rm -rf /usr/local/lib/node_modules

Node.jsバージョン管理ツールのアンインストール

バージョン管理ツールが複数入っていてもいいことはありません。入っているものをすべてアンインストールしていきます。インストールしたツールを覚えていない場合はecho $PATHでn, nvm, nodebrew, fnmなどが関わっていそうなディレクトリにPATHが通っているか確認したり、which xx(各コマンド)でコマンドの有無とインストール先を確認しましょう。

n, nvm, nodebrewのアンインストール

私はmacOSでhomebrewを利用していたので次のコマンドでアンインストールしました。

> brew uninstall xx

xxは各ツールに置き換えて下さい。

fnmのアンインストール

fnmはfishermanでインストールしたプラグインなので、次のコマンドでfnmをアンインストールしました。

> fisherman rm fnm

これまでの使用状況もクリーンアップしたい場合は次のコマンドも実行しましょう。*1

> rm -rf /Users/ユーザ名/.config/fnm

fnmのインストール

fnmはfisherman経由でインストールするプラグインです。次のコマンドでインストールしました。*2

> fisher add fnm

最後に

試行錯誤してローカル開発環境がとっちらかってしまった場合は定期的にリフレッシュしましょう。

*1:私はfnmフォルダ以下に手を加えており、余計なエラーが発生しそうだったため、削除しました

*2:fnmの使用方法は https://qiita.com/shuuji3/items/8819f237a2ed31369607#fnm-%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9 こちらに固まっています

Node.jsを用いた開発環境におけるパッケージアップデート不全の調査

最近Node.jsを用いるローカルの開発環境を整えていました。そのときにパッケージがアップデートできない問題に遭遇し少々ハマりました。そのため、未来の自分のためにも備忘録的に対応の手順を書き残しておきます。

環境

※fish・fisherman導入についてはQiitaに投稿しています。

アップデート不全発生

npm install -g @angular/cliでアップデートしても利用する@angular/cliのバージョンが変わらない(ng versionの結果が変わらない)

調査

アップデート自体は正常終了しているため、呼び出している@angular/cliとアップデートしている@angular/cliとが別のものである可能性があります。それを調査します。

コマンド:npm install --save-dev @angular/cli

カレントディレクトリで開発用にインストールした場合に最新バージョンがインストールされ、利用可能になるか試しました。インストールは正常終了し、最新バージョンが利用可能になりました。これにより、ローカルインストール*1では問題ないことが判明しました。

> npm install --save-dev @angular/cli
~中略~
[fsevents] Success: "/Users/ユーザ名/.config/fnm/lib/node_modules/@angular/cli/node_modules/fsevents/lib/binding/Release/node-v64-darwin-x64/fse.node" is installed via remote
+ @angular/cli@7.3.3
added 363 packages from 196 contributors in 26.312s

> ng version

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/


Angular CLI: 7.3.3
Node: 10.15.1
OS: darwin x64
Angular:
...

コマンド:npm uninstall -g @angular/cli & npm install -g @angular/cli

前述のローカルインストールを操作したディレクトリとは異なるディレクトリで、@angular/cliを再インストールしました。アンインストールとインストールは正常に完了しました。

>npm uninstall -g @angular/cli
removed 363 packages in 5.499s

>npm install -g @angular/cli
/Users/ユーザ名/.config/fnm/bin/ng -> /Users/ユーザ名/.config/fnm/lib/node_modules/@angular/cli/bin/ngatus

> fsevents@1.2.7 install /Users/ユーザ名/.config/fnm/lib/node_modules/@angular/cli/node_modules/fsevents
> node install

node-pre-gyp WARN Using needle for node-pre-gyp https download
[fsevents] Success: "/Users/ユーザ名/.config/fnm/lib/node_modules/@angular/cli/node_modules/fsevents/lib/binding/Release/node-v64-darwin-x64/fse.node" is installed via remote
+ @angular/cli@7.3.3
added 363 packages from 196 contributors in 21.983s

ログのインストール先のディレクトリを見るに、fnmを介してインストールしていそうです。

コマンド:which ng

このコマンドにより、ngがどこを参照しているか確認できる。実際の結果は次のとおり。

> which ng
/usr/local/bin/ng

バージョンマネージャのfnmを介していないように見えます。/usr/local/bin/ngを閲覧することで、さらに詳細にどこのコマンドを呼び出しているか確認できます。(当記事では割愛)

コマンド:which xx

特に問題が発生していない他のnpm管理下のパッケージを確認することで、本来どこを参照しているのか確認します。*2

> which xx
/Users/ユーザ名/.config/fnm/bin/xx

fnmを介してアクセスする場合は、パスからfnmを介していることが明らかにわかるようです。

調査結果より

「ローカルインストールでない@angular/cliにアクセスする際のngコマンドは、参照先を誤っている」と言えそうです。

この結果から、そもそものグローバルな環境にNode.jsや利用するパッケージが存在する。そして、ngコマンドの際にはそちらを参照しているのではないか?と推測できました。実際に他のパッケージでもグローバルな環境に存在するもの*3はngと同様にアップデート不全が発生していました。

対策

一度グローバルなNode.js環境とfnmによるNode.js環境の両方をクリーンアップしてfnmを導入し直すことにしました。*4

※クリーンアップとfnmの再導入については別記事で公開予定です。

最後に

バージョン管理ツールを導入するときは既存のものをちゃんとアンインストールしてからにしましょう。もし、バージョン管理ツールが面倒ならdockerで環境構築しましょう。

ngmt83.hatenablog.com

*1:任意のディレクトリのみでpackage.jsonに指定したパッケージをインストールする方法

*2:fnmのドキュメントや実装を確認する方がより確実です

*3:ls /usr/local/lib/node_modules/ で確認可能

*4:PATHを通し直すなど、Node.jsで利用するパッケージの参照先を変更もできたが煩雑だったためやめました

簡単なChrome拡張機能(Extension)のmanifest.jsonの書き方

先日Chrome拡張機能をリリースしました。

chrome.google.com

かなり単純で作成も簡単だったのですが、拡張機能作成において唯一独特なmanifest.jsonについて解説します。今回はわかりやすさのために最小限の構成で解説します。

※実際に作って理解するのもおすすめです。その場合は公式のチュートリアルをおすすめします。

最小限の構成で作れるもの

解説するのは拡張機能のほぼ最小限の機能しか使わない場合のmanifest.jsonです。具体的には下記の通りです。

最小限のmanifest.json

{
  "manifest_version": 2,
  "name": "Tweet Hider",
  "version": "1.0",
  "content_scripts": [
    {
      "matches": [
        "https://twitter.com/*"
      ],
      "js": [ "content-script.js" ]
    }
  ],
  "icons": {
    "128": "images/icon-128x128.png"
  }
}

1つずつ簡単に説明していきます。

manifest_version

manifest.json自身のバージョンですが、現状有効なものは2しかないため、何も考えず2にしてかまいません。

name

拡張機能の名前です。任意の名前をつけましょう。

version

拡張機能のバージョンです。リリースを積み重ねれば上がっていくあれです。

content_scripts

指定URLで自動実行する場合に設定が必要です。ここの設定が拡張機能の動作を決めるため、設定可能な項目は多いです。(今回は最小限の設定のみ)

matches

スクリプトを動作させたいURLをここに記述します。例のように*でまとめて指定することもできます。詳細はMatch Patterns - Google Chromeを参照して書きましょう。

js

動作させるスクリプトを指定します。私はjQueryを使用することが多いので、つぎのように合わせて指定します。

"js": [ "jquery-3.3.1.min.js", "content-script.js" ]

これによって、自作するスクリプトでもjQueryが使用できます。

icons

拡張機能のアイコンを設定します。複数サイズ用意するのがよいですが、とりあえず1サイズだけでも用意しましょう。

最後に

今回はかなりシンプルな拡張機能の前提でmanifest.jsonの解説をしました。実際には多くの設定項目が存在し、混乱してしまうこともあるので、シンプルなものから挑戦し、少しずつ覚えていくといいと思います。