日々の回復力を最大化するささやかな抵抗

  1. 1. なぜなに回復力
  2. 2. 体と心の相関と体をないがしろにしないこと
  3. 3. 回復しやすくするために実践してること
    1. 3.1. 筋トレをする
    2. 3.2. ストレッチをする
    3. 3.3. 暴飲暴食をしない
    4. 3.4. 目薬をさして目を温める
    5. 3.5. お風呂でマッサージする、特に頭皮
    6. 3.6. 寝る前に養命酒を飲む
  4. 4. 最後に

始めに言っておきますが、最近テック系の話ばかり書いてきましたが、このブログはテック系寄りの雑記ブログなので今日はあまりテックと関係ないことを書きます。久々です。

最近の僕はというと、仕事のプロジェクトがなかなか佳境にさしかかって帰りが遅くなってきてます。それに加えてプライベートのほうもいろいろなことがおきていて、なかなか大変になってきました。
そんな毎日を乗りきるために「回復力」に焦点を当てたお話です。

忙しい毎日をのりきるための戦略として、

  • 最大体力を上げる
  • 回復力を上げる

という2つの戦略があると思いますがその後者のお話です。

ちなみに医学的な裏付けはとってませんので「僕はこうしてますよ」という1つの参考意見以上にはならないのでご注意ください。

なぜなに回復力

加齢により体力がなくなった、と昔武術に明けくれて今でも同年代の人よりも少しだけ体力に自信のある僕も感じます。でもつきつめて考えると最大HP的な体力がなくなったというよりは、減った最大HPが自然回復していくスピードが落ちたなと僕は実感しています。

体と心の相関と体をないがしろにしないこと

科学的に本当のところはどうかは知らないんですが、僕は体と心は相関関係があると思っています。腹が減ってるだけでちょっと怒りっぽくなることもあるし、今だったら花粉などのアレルギー症状が出てるだけでも少しイライラすることでしょう。冷えも禁物です、体温が下がると機嫌も体調も悪くなります。

いくら理性が発達しても、人間はしょせんヒトという生き物で、僕はまずそこを違わないように気をつけています。僕は心はどうコントロールすればできるのか良いかわかりません。でも体はわりとコントロールしやすいので、気持ちをハンドリングしたいときには体を介したアプローチをとるようにしています。これのわかりやすい例が深呼吸です。

ということで

  • なんだか疲れてる
  • 精神的に追いこまれてる
  • しんどい

という気持ちでいる日常であったとしても、とりあえず肉体を

  • 筋肉が疲労しすぎてたりや内臓が疲労していない状態
  • 肉体を抵抗なく動かせる状態
  • 身体の一時的な不便や痛みが気持ちに悪影響を及ぼしていない状態

に保つというアプローチはかなり有効だと思っています。

毎日を機嫌良く過ごすのはもちろん、判断力や決断力、心理的に障壁がある場合の踏み込む力にも影響しそうなので、体の心地良い状態に保つ戦略は良さそうに思います。特に長期的な視点で考えたときにその積み重ねは大きな差を生みそうです。

余談ですが僕にとっては一番良くないのは「疲れているから」という言い訳を用意できてしまうのが危ないです。僕はそこまで気持ちが強くないのでしばしば逃げ道を自分で塞ぐ戦略を取ることがあります。「疲れている」という使い勝手最強レベルの言い訳ができてしまうといろんなことが疎かになるので、疲れていない状態に保つのはけっこう重要だと感じています。

回復しやすくするために実践してること

筋トレをする

筋肉が増えることで体を楽に動かせたり、ということはもちろんあります。筋肉は全てを解決する、というなかば笑い話のような理論もありますが、僕はあながち間違いではなく7割ぐらいは解決してくれると思っています。

そんな話はさておき、コリの原因が筋肉が硬ばって血流が滞ってるということならば意識的に筋肉を動かしてみよう、というアプローチです。適度な運動はしたほうがいい、というのはもはや常識にもなっているはずです。

僕の場合は筋肉痛になるまでしてしまいますし、その筋肉痛を不快に思わず逆にトレーニングした実感として快と感じることもあるのですが、運動強度には気をつけてください。筋肉痛が酷いと普通は不快になって逆効果かもしれません。ですが、しっかり運動して筋肉を使って動かして、その結果寝付きが良くなったり眠りが深くなる効果も見逃がせません。特に頭を使う仕事の場合、いろいろ考えたりして睡眠の質が悪い場合など肉体疲労状態を意識的に作りだして強制的に眠りの質を上げる方法はあながち捨てたもんあじゃありません。

他の効果としてテストステロンの増加とか、トレーニング後の達成感がメンタルに効いたりしますが、そんな話はまた別の機会で。

ストレッチをする

筋トレに近いんですが、筋肉をのばしてあげる。これだけでも十分に効果があります。
簡単なヨガ的な大層だったり、ラジオ体操でも良いですね。習慣に無いと「めんどくさい」と思ってしまいますが時間にして5分とか10分ぐらいで十分。筋トレもそうですが、面倒なことってだいたい心理的障壁があるだけで実作業や実時間にすると大したことないんですよね。

ちなみにヨガをすると痩せるとか言いますが、だいたいヨガの動きはアイソメトリックな筋トレとストレッチの融合なので無理なく実践できる運動をした結果、健康指向になって普段の意識が変わり、結果的にに痩せた、というだけの話だと思っています。

暴飲暴食をしない

本当に加齢によって油っこいものがツラくなってくるんですね。まさか焼き肉行ってカルビを敬遠する日が自分に訪ずれると思いませんでした。

過ぎたお酒は眠りの質を悪化させますし、消化しきれない食べすぎもまた同様なようです。良く噛んで腹八分目、これを心掛けると内臓も疲労しにくく、眠りが消化のためだけに使われなく良い感じな気がします。睡眠という回復手段の効率を最大化させるための戦略ですね。

可能であれば早い時間に夕食を摂るのも有効なんですが、忙しいとどうしても帰宅が遅くなってしまって現実的に実行が難しかったりするのでそこはあきらめました。

目薬をさして目を温める

デスクワーク主体だと基本的に目が酷使されるので寝るときにやります。
眼精疲労に効く目薬をさして目元をあっためる系の何か(電熱系やらレンジや使い捨てなどいろいろ)を使う、これがなかなかに効きます。

寝るときにやると眠りやすくなる効果もあります。ちなみに僕はけっこう疲れてくると仕事のお昼休みにもやります。スッキリしていい感じです。目の疲れとともに目から耳のちょっと上辺りのコリが解れるような。

お風呂でマッサージする、特に頭皮

体のコリのあるところマッサージするぐらいはよくやると思うんですが、考えごとを沢山した日、目を酷使した日は頭皮もやります。頭皮は意外に忘れがちですが、脳や目の酷使は頭皮に来る気がしています。美容院に行ったときのマッサージを想像していただければわかりやすいかと。

ちなみに顔マッサージや耳をひっぱったりも良さそうですよ。とにかく張ってるところを緩める。マッサージやストレッチはコレです。人間、力の入れ方を学ぶことは多いんですが力の抜き方を学ぶ機会はそうそう無いんです。緩めるのは下手なんです。だから意図して緩めてあげる必要がありますね。

寝る前に養命酒を飲む

もうこの記事はこれが言いたくて書いたようなところがあります。それぐらい効きます(完全に体感でのお話です。体感は個人差があります)。
養命酒はイメージからどうも高齢者用に見られますし僕も以前はそう思ってました。ですがもしかしたら働き盛りの世代こそバッチリなのかもしれません。
もしかしたら栄養ドリンク系も同様の効果なのかもしれませんが、栄養ドリンクは多量のカフェインを含んでたりするので睡眠の質が落ちますし、場合によっては寝付けないこともあるかもしれません。

ただし少量のアルコールを含むため、体質的にアルコールが全く分解できないほうは要注意ですね。

最後に

見返してみると至極当たり前のことしか言ってないですね。ただしその当たり前をちゃんとやるか、意識的に実践するか、は長期戦を闘ううえで重要になると踏んでいます。

僕の実年齢はそう若くはないので若くて優秀な面々と張り合っていくにはこういう地道な方法もないがしろにできないな、と思っています。1年は1日×365。

肉体的にも精神的にも適度な負荷をかけつつ、日々を楽しく機嫌良く、うまいこと乗りきっていこうと思います。

Google App ScriptをTypeScriptとClass構文で書く - 実装

  1. 1. TL;DR
  2. 2. 想定
  3. 3. 開発
    1. 3.1. 基底クラスのconstructor
    2. 3.2. 基底クラスのメソッド
    3. 3.3. 継承したクラスを作る
    4. 3.4. Webhookをトリガーにしてクラスとそのメソッドを使う
  4. 4. デプロイと注意点
    1. 4.1. 注意点
      1. 4.1.1. GASでES6のimport/exportは使えない
      2. 4.1.2. デプロイと本番化
  5. 5. 最後に

前回は「Google App ScriptをTypeScriptとClass構文で書く - 環境導入」ということでClaspでローカル開発した場合の恩恵と、どう環境を設定したらいいかという話を書きました。

今回はES6から使えるようになったClass構文をつかって、TypeScriptでうまいことGASを書いていきます。本題です。
ちなみにこのClass構文はJSがそもそも持つprototypeの実装を簡単に書ける糖衣構文という位置付けです。

また、今回はTypeScriptに不慣れな人でもわかりやすくするためあえて型に関しての記述は少なくしました。慣れているほうは型をどんどん利用するともっと書きやすくなるのでオススメです。

Claspが正式にTypeScript対応してくれて事前ビルドなくtsをそのままpushできるようになって非常に楽になりました。その事情から逆に発生してしまっている特有の落し穴についても最後のほうで触れています。

TL;DR

  • GitHubのイベント(PRなど)をWebhookで受けてChatworkに通知するサンプル
  • ES6のClassと継承使うと責務の分離と共通動作の取り回しがしやすくなる
  • GAS(Clasp)+TypeScript特有の落とし穴があるから気をつけろ

想定

サンプルの題材としてGoogleSpreadSheetをDB的に扱って、その情報を参照して自動化する想定をします。例として、GitHubのプルリクエストの状態に応じてChatworkに通知をしてみます。具体的にはプルリクエストの状態の変化時にWebhookが飛ぶのでそれをGAS側で受けて、Chatworkの通知にしています。

SpreadSheetとしてはこんなかんじでシート2つあります。

  1. members: メンバーの名前、ChatworkのID、GitHubのIDを持っている名簿的なシート
  2. repositories: リポジトリ名、リポジトリのURL、対応する通知先のChatworkルームID

ちなみに各SpreadSheetの1行目は各カラムのタイトル行とします。

最終的にやりたいことは、登録したリポジトリでプルリクエストに変化があったらChatworkの指定したルームに関係者にToをつけて通知する、という流れです。これを細かくすると、

  1. GitHubでPRのイベントをトリガーとしてGASにWebhookを飛ばす(GitHub側で設定)
  2. GASで受けてWebhookの内容をパースする
  3. パースした内容にしたがって通知メッセージや通知先をGoogleSperedSheetから取得する
  4. Chatworkに通知する

という流れになります。

開発

基底クラスのconstructor

まず基底クラスとしてGasSheetというクラスを作ってみます。
こいつの役割は、各シートを扱うための情報の読み込みと検索、書き替えの機能を提供します。

GASのAPIでSpreadSheetのデータを範囲でとってきた場合、2次元配列になります。
したがって、例えば上の画像の名簿データは

[
['cwID', 'name', 'githubID'],
['1111111111111', '雨宮 蓮', 'joker'],
['2222222222222', '坂本 竜司', 'skull'],
['3333333333333', '高巻 杏', 'panther'],
// 中略...
]

という配列の中に各行が列ごとに値を区切られた配列として取得できます。

今回はこれだと扱いづらかったので、まずはGasSheetクラスをnewして生成したときに、
シートのデータをカラム名をキーに持つオブジェクトに変換して格納することにしました。

とりあえずnew GasSheet(sheet)な感じでシートを受けとって処理できるようにしてみます。

01_GasSheet.ts
export default class GasSheet {
sheet: any // SheetClass from GAS
columns: { columnNum: number; name: string }[]
data: {}[]
constructor(sheet) {
this.sheet = sheet
const rawColumns: any[] = sheet
.getRange(1, 1, 1, sheet.getLastColumn())
.getValues()[0]
const columns: { columnNum: number; name: string }[] = []
rawColumns.forEach((dataOfColumn, idx) => {
columns.push({ columnNum: idx + 1, name: dataOfColumn })
})
const rawData: any[][] = sheet
.getRange(2, 1, sheet.getLastRow(), sheet.getLastColumn())
.getValues()
const data: {}[] = []
rawData.forEach((dataOfRow, idx) => {
const obj = { rowNum: idx + 1 + 1 } // 行番号は1スタート + HEADERの行
columns.forEach((column, i) => {
obj[column.name] = dataOfRow[i]
})
data.push(obj)
})
this.columns = columns
this.data = data
}
}

使うときはたとえば

const SHEETS = SpreadsheetApp.openById(ここにスプレッドシートのID)
const MEMBERS_SHEET = SHEETS.getSheetByName(`members`)
const gasSheet = new GasSheet(MEMBERS_SHEET)
console.log(gasSheet.data[0])
// => { rowNum: 2, cwID:'111111111', name:'雨宮 蓮', githubID:'joker'}

みたいな感じですね。

基底クラスのメソッド

これだとまだ機能的にはオブジェクトの形になるようにラップしただけなので、メソッドから各データを取れるように実装してみましょう。

ちなみに配列、オブジェクト、コレクションを扱いやすくするためGASのライブラリとしても用意されているUnderscoreを使います。Underscoreにならって、今回は

  • where: 引数で指定したキーの値が合致する複数のオブジェクトを配列に入れて返すメソッド
  • findWhere: 引数で指定したキーの値が合致した最初のオブジェクトを返すメソッド

の2つを実装してみます。なお、本来なら見つからなかった場合など中でエラーハンドリングすべきですが、今回は省略します。

00_GasSheet.ts
const _ = Underscore.load() // Underscoreライブラリのロード
export default class GasSheet {
sheet: any // SheetClass from GAS
columns: { columnNum: number; name: string }[]
data: {}[]
constructor(sheet) {
// 中略(上で紹介した通り)
}
where(keyValue): {}[] {
return _.where(this.data, keyValue)
}
findWhere(keyValue): {} {
return _.findWhere(this.data, keyValue)
}
}

そして使うときは

const SHEETS = SpreadsheetApp.openById(ここにスプレッドシートのID)
const MEMBERS_SHEET = SHEETS.getSheetByName(`members`)
const gasSheet = new GasSheet(MEMBERS_SHEET)
console.log(gasSheet.findWhere({name: '坂本 竜司'}))
// => { rowNum: 3, cwID:'222222222', name:'坂本 竜司', githubID:'skull'}

みたいな感じです。

継承したクラスを作る

GasSheetクラスができたので、これを利用した別のクラスを作っていきます。既にオブジェクト指向的な言語に触れてる方にはいまさら説明の必要がないかもしれませんが、GASはいろいろな人が触っているようなので簡単に説明します。

例えばAというクラスを継承したA-1、A-2というクラスを作ったとします。AクラスがもつメソッドはA-1,A-2ともなにもせずとも使えます。ですがA-1だけのメソッドはA-2では使えません、逆もそうです。すごいざっくり言えば共通したいところは共通化すること、共通化しないところは個別でしか使えないという責務の分離の両方を実現できます。

じゃあ実際にやっていきます。

方針として、GasSheetクラスを継承させてMembersSheetクラスとRepositoriesSheetクラスを作っていきます。MembersSheetクラスは単純に任意の値から該当するデータを取得すればいいのでシンプルに継承したもの、Repositoriesクラスにはnotifyというメソッドを作って通知できるように実装します。

01_MembersSheet.ts
import GasSheet from './00_GasSheet'
const SHEETS = SpreadsheetApp.openById(ここにスプレッドシートのID)
const MEMBERS_SHEET = SHEETS.getSheetByName(`名簿`)

export default class MembersSheet extends GasSheet {
constructor() {
super(MEMBERS_SHEET)
}
}

MembersSheetはこれだけでOKです。注目すべきは、extends GasSheetと継承しているところ、そしてconstructor()は引数を使ってないところです。
superは継承元(GasSheetクラス)の同名メソッドを呼びますので、super()に引数をわたすことで先程の例でやっています。

const MEMBERS_SHEET = SHEETS.getSheetByName(`members`)
const gasSheet = new GasSheet(MEMBERS_SHEET)

と同じことをしています。

こうすると使うときは先程よりもシンプルになって

const membersSheet = new MembersSheet()
console.log(gasSheet.findWhere({name: '坂本 竜司'}))
// => { rowNum: 3, cwID:'222222222', name:'坂本 竜司', githubID:'skull'}

とするだけでOKになります。

次にRepositoriseSheetクラスを作ります。前半はMemberslSheetと同様です。

02_RepositoriesSheet.ts
import GasSheet from './00_GasSheet'
const SHEETS = SpreadsheetApp.openById(ここにスプレッドシートのID)
const REPOSITORIES_SHEET = SHEETS.getSheetByName(`repositories`)
const gasSheet = new GasSheet(REPOSITORIES_SHEET)

export default class RepositoriesSheet extends GasSheet {
constructor() {
super(REPOSITORIES_SHEET)
}
notify(notification) { // notification = {repo: url, to: id, message: msg }
// 最初にrepositoriesのシートからURLによりどのプロジェクトか特定する
const repo = this.findBy({repositoryURL: notification.repo})
// メッセージを引数で来たオブジェクトを使って整形する
const message =`[To:${notification.to}][info][title]${repo.name}[/title]${notification.message}[/info]`
// ライブラリ経由でAPIを叩いて通知する
const client = ChatWorkClient.factory({ token: ここにCWトークン })
return client.sendMessage({
room_id: repo.room_id,
body: message,
})
}
}

ChatWorkClientは非公式ですが、Chatwork通知用のライブラリがあるのでそれを使っています。
cw-shibuya/chatwork-client-gas: Chatwork Client for Google Apps Script

notifyメソッドでやっていることは、notificationという仮引数の名前でオブジェクトとして引数で、リポジトリのURL、 通知するメンバーのID、通知内容を取ります。

それにしたがって、メソッド内で適切な形にメッセージ内容や通知を飛ばす先のルームを設定しています。Chatworkでは[To: ID][title]などの独自タグで通知先や強調表示できます。普段Chatworkを使っていないほうは適宜そんな感じか、となんとなく見てください。

ここでのポイントthis.findBy()です。findByは継承元のGasSheetクラスに実装してあるので、使うことができます。つまりリポジトリシート情報からURLが合致するリポジトリの情報を取得しています。

CWトークンはコード内にベタで書くよりはPropertiesServiceなどを環境変数的に利用するのが良いと思いますが、ここでその説明は割愛します。

Webhookをトリガーにしてクラスとそのメソッドを使う

あともう一息ですね。ここまでで必要なクラスができたので、実際にWebhookを受けてメッセージを飛ばす実装をしていきます。

今回はサンプルとしてあるプルリクエストがマージされたときに通知するとしてみましょう。

GASの仕様でWebhookとしてリクエストが飛んできたものはdoPost()関数で受けることができて、その時のbodyに入ってくる内容は引数に渡せます(今回はeとして扱う)それを一旦パースして、そのあとで使いやすくしています。

doPost.ts
import MembersSheet from './01_MembersSheet'
import RepositoriesSheet from './02_RepositoriesSheet'
export function doPost(e) {
const contents = JSON.parse(e.postData.contents)
// membersシートを扱う準備
const membersSheet = new MembersSheet()
// membersシートからgithubIDの該当する人を探す
const membrer = memberSheet.findBy({githubID: contents.sender})
// repositoriesシートを扱う準備
const repositoriesSheet = new RepositoriesSheet()
// 通知内容をオブジェクトとしてまとめる
const notification = {
repo: contents.repositoryUrl,
to: member.cw_id,
message: `${contents.title}がマージされました!`
}
// repositoriesシートを使って通知を実行する
repositoriesSheet.notify(notification)
}

実装的にはMemberSheetクラスをインスタンスでwebhookに載ってきた情報からGitHubのIDから通知先をメンバーを特定します。

RepositoriesSheetクラスのインスタンスを作って、先程実装したnotifyメソッドに必要な情報を引数として渡しています。

ここでマージの場合はこう、レビューの場合はこう、みたいなハンドリングを省略しましたが、もしやりたい場合は書く必要があります。文章の出しわけも同様ですね。
今実際動いているものはシートのクラスとは別に例えばGitHubEventというクラスを作ってうまいことやるようにしています。

デプロイと注意点

注意点

あとは上記のスクリプト郡をデプロイすればいいだけですが、ここでGAS+TypeScript特有の落とし穴があります。

GASでES6のimport/exportは使えない

まさかと思いますよね、マジなんです。
じゃあ上のコードでimport/exportしてるのはなんでだ、って話なんですがこれはエディタの補完を効かせたりLintのためだったりです。実際$clasp pushするとコメントアウトされます。

さらにその特殊な事情として

import {
functionA,
functionB
} from `fileA`

みたいに書くとそのコメントアウトもまさしく働かくなってしまうのでやっちゃだめです。かなり罠です、お気をつけください。importを書くときは1行に書くのはGASでやるときは守っておいてください。

で、じゃあどうやって別ファイルに定義したものを使えるかというとGASは別ファイルに定義したものも他ファイルで使える全てがグローバルな仕様です。なので動かすだけならimportexportはいりません。
つまりimport/exportは使えないが結果的に同じことは実現できている、という状況です。

またimportがすべてコメントアウトされるためimportによる定義もできてません。なので、通常は自由な名前で定義できるところをClass名と厳密同じ名前でimportするようにします。

GasSheet.ts(export側)
export class GasSheet {
// 略...
}

import側
// ◯ 良い
import GasSheet from './GasSheet'

// × ダメな例(export時の名前と違う
import MySheet from 'GasSheet`

さらにこの仕様につながって、どうやらファイルはファイル名順に読み込まれ、読み込み前のものは使えない、という仕様があるっぽいです(要出展)。
なのでこのご時世としてはやりたくないですが、01_とか読み込まれて欲しい順でファイル名をつけます。

もう1つあります。直接使われる関数(e.g. doPost())はexport defaultしちゃうと上手く動きません。exportがある分には大丈夫ですがexport defaultとして宣言してはだめです。そういうこともあって先程のdoPost

export function doPost(e) {
// 中略
}

として定義しています。

デプロイと本番化

ClaspとGASの連携の話になりますが、通常Clasp経由でGASのコードを更新するには

$ clasp push

とします。これでGASのスクリプトエディタで開くコードが更新されます。もし開いたままだったらリロードしてください。

ちなみにClaspがTypeScript対応したことによる事前にtscなどは必要ありません。pushすると.tsファイルは.gsにトランスパイルされてアップロードされます。

ここでの注意点はなんか上手く反映されないときがあるので、リロードしたあと一度スクリプトエディタ上で保存すると上手くいくことがあるようです。このへんの挙動は謎です。

単純にGASにコードを追いて手動実行したりする場合はこれだけでいいんですが、Webhookを受けとるような場合ではWebアプリケーションとして公開する必要があります。また、公開するには版(バージョン)としてデプロイされていることが必要です。このため

$ clasp deploy

を実行します。この時引数をつけないで実行すると新しい版としてデプロイされます。

あとはGASのスクリプトエディタのほうで、公開 > Webアプリケーションとして導入とします。
この時に表示されるURLがWebhookを受けるURLなのでコピーしておいてGitHub側に設定します。
プロジェクトバージョンは先程デプロイしたときに発行されたバージョンを指定します。
他の権限の設定はやることによって最適なものが変わるので、設定します。

最後に

今実際に僕が動かしてるものはもうすこし多様性を持たせた結果、サンプルで扱うにはデカすぎるようになってしまったので公開して紹介が難しく残念です(もし改変して公開できる余裕ができたらぜひやりたい)

あと次回、もし続けばテストについて書けたらいいなあと思っています。

GASってVBA的に捉えてる層もいれば、JS系で書けるWebアプリとか自動化できるおもちゃみたいに考えてる層もいます。
この記事はそんな隔絶した層のちょうど溝を埋めるような記事として読まれたらいいなあ、と思っています。

Google App ScriptをTypeScriptとClass構文で書く - 環境導入

  1. 1. TL;DR
  2. 2. なんでやるの?
  3. 3. 開発環境
    1. 3.1. Linterとフォーマッターを導入する
      1. 3.1.1. ESLintでTypeScriptにLintをかける
      2. 3.1.2. ESLintにPrettierも組み込む
      3. 3.1.3. もっと細かい設定
    2. 3.2. 型定義の導入
      1. 3.2.1. GAS用ライブラリの型定義

GASは本当に手軽で便利。ほんのちょっと自動化したい、でもDB立てて、サーバー立ててまでやるのもなぁ、ってときにその溝を埋めてくれる良いところに収まってる感じがしますね。特にGoogleスプレッドシートとの連携もしやすいからスプシを簡易DBとして見たててやるとけっこういろいろできちゃう。

そんな感じで職場の社内ツール的なものをGASで作ってたりするんですが、昨年後半にClasp経由でTypeScriptがサポートされたのでちゃんと書きなおしてみました(以前はWebpackでやっていました)。それが一段落したのでせっかくなのでその知見をご紹介しようと思います。

書いてたら長くなってしまったので、いくつかに分けます。まずは環境構築から。

TL;DR

  • GoogleAppScriptはClasp経由でローカルで開発できるぜ
  • ローカルで開発できるってことはGitが使えたり、静的解析も使えるぜ
  • TypeScriptにも対応してるのでいろんな恩恵があって最高だぜ
  • そんなことを実現するための設定を今回は紹介するぜ

なんでやるの?

まずなんでこの路線で開発するか、というポイントは

  • TypeScriptはES6な書き方ができる
    • ESLint(TSLint)、Prettierなども使える!
    • Class構文便利!
      • ちゃんと継承もできるんだぜ
  • TypeScriptの型サポートがあると書きやすい
  • TypeScriptがサポートされたから面倒なWebpackが要らなくなった

ES6による恩恵が一番大きいので、以前からWebpackでやっていた場合は大きな変化ではないですが、Clasp側でサポートされたことによって自前でビルドする手間もなくなったのが大きいですね。
特にWebpackは時に設定がややこしく、そこでつまる人も多いと聞くので脱WebpackしつつもES6の恩恵を受けれる環境ができあがったのが嬉しい限りです。

開発環境

まずなにはともあれClaspを入れます。これは通常Web上のスクリプトエディタでGASのコードを書いていくのではなく、ローカルのファイルとしてスクリプトを書けるようにしてくれるものです。
ローカルで扱えるというだけで様々な利点があります。

  • Gitが使える
    • バージョン管理が楽になる
    • つまりもちろんGitHubによる共同開発環境が持てる
  • ESLint(TSLint)、Prettierなどの静的解析によるフォーマット、リントが効く
    • 間違いが減ったり、自動修正したり
  • 好きなエディタが使える
    • 捗る!

ここでは詳細なClaspの導入、GASとの反映方法は割愛します。公式のREADMEやちょっとググればいろいろな導入記事が出てくると思いますのでそちらをご参照いただればすぐできると思います。

あ、ちなみにNode.jsも必須です。その導入もここでは触れません。

今回の開発で特殊な事情を加味して言及するとこんなディレクト構成になります

.
├── __tests__
│   └── 各種テスト用ファイル
└── node_modules # ライブラリ格納ディレクトリ
└── src
│   ├── *.ts # これから作っていくTypeScriptファイル
│   └── appscript.json # GASの設定ファイル
├── .clasp.json # claspの設定ファイル
├── .claspignore # clasp用のignoreファイル
├── .eslintrc.js # 後述するESLint用の設定ファイル
├── .gitignore
├── index.d.ts # 型定義ファイル
└── package.json # プロジェクトの設定ファイル

とこんな感じですかね。テストは書かないんだったらないですが、せっかくローカルで開発するならテストも書きたいところです。
なので環境を整えた後はsrc/以下にガリガリ実装していく感じです。注意すべき点としてはGASの設定用のappscript.jsonはこのsrcディレクトリ内に置くことになるところです。

Linterとフォーマッターを導入する

いくつか選択肢はあると思いますが、今回は

  • ESLint経由でTypeScriptのLintをする
    • 理由: TypeScript側が「LintはESLintを使ってくれよな」って言っている
  • ESLint内でPrettierによるフォーマットをかける
    • 理由: Lint側とバッティングするルールがあるので上手く避ける

という方法で行きたいと思います。

一応TypeScriptでTSLintではなくESLintを推奨している経緯は

のLintの項目、もしくはThe future of TypeScript on ESLint - ESLint - Pluggable JavaScript linterを参照していただければと思います。

ESLintでTypeScriptにLintをかける

yarn add --dev eslint
yarn add --dev @typescript-eslint/eslint-plugin
yarn add --dev @typescript-eslint/parser

で、ESLintとESLint経由でTypeScript対応するプラグインとパーサーを入れます。
そしたら.eslintrc.jsというルール設定のファイルを作って、

.eslintrc.js
module.exports = {
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
}

と入れます。これが最小限の設定ですね。

これで.eslintr.js内にTypeScript用のLint設定も書いて設定ができます。

ESLintにPrettierも組み込む

ESLintの設定のいくつかはJS系の最有力フォーマッタであるPrettierと一部バッティングするルールがあります。
これが整合性が取れてないと、自動でPrettierのフォーマットとesLint --fixを連続してかけたりエディタの設定でFixOnSaveとかやってると矛盾ルールでハマります。

ということで個人的なオススメとして、eslint --fix内でPrettierをかける設定にするのが良いと思っています。またVSCodeなどでESLintのfixOnSave設定だけでキッチリPrettierもかかります。

具体的には

yarn add --dev prettier
yarn add --dev eslint-plugin-prettier
yarn add --dev eslint-config-prettier

eslint-plugin-prettier.eslintrc.js内でPrettierの設定もできるようにするもの、eslint-config-prettierはESLint側のPrettierのフォーマットルールとバッティングするルールをオフにするものです。

となると、設定は

.eslintrc.js
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
parserOptions: {
sourceType: 'module',
},
plugins: [
'@typescript-eslint',
'prettier',
],
extends: [
'prettier',
'prettier/@typescript-eslint',
],
rules: {
'prettier/prettier': ['error', {
useTabs: false, // example
}],
'no-var': 'error', // example
'@typescript-eslint/camelcase': 'error' // example
},
}

みたいな感じが最小になりますかね(Ruleに関してはサンプルで入れています。適宜カスタムしてください)。

このあたりのことはIntegrating with ESLint · Prettierを参照していただければわかりやすいかと思います。

もっと細かい設定

ここはオプショナルな設定ですが、用意されているルールなどを適用したい場合は、もうちょっと込み入ってきます。僕はStandard(JavaScript Standard Style)派なんですが、例えばそれを適用しようとするなら、standard/eslint-config-standardを使いますので、

yarn add --dev eslint-config-standard eslint-plugin-standard eslint-plugin-promise eslint-plugin-import eslint-plugin-node

として.eslintrc.jsのextendsに'standard'を加えます。Standardにはno-undefルール(定義されていないものに警告するルール)が入ってますので、GAS特有の関数(e.g. SpreadsheetApp)が警告されます。

.eslintrc.jsglobalsに設定してあげればいいんですが、それなりの数があるのと思うので、selectnull/eslint-plugin-googleappsscriptを使ってガっと回避します。

ちなみにオブジェクト操作のライブラリUnderscore.jsや日付を扱うライブラリMoment.jsがGASでも用意されてますが、使う場合は同じようにグローバルな関数になるので、それは.eslintrc.jsglobalsで設定していきます。

そうなるとこんな感じになります

.eslintrc.js
module.exports = {
root: true,
env: {
'googleappsscript/googleappsscript': true,
},
globals: { // example
Underscore: true,
Moment: true
},
parser: '@typescript-eslint/parser',
parserOptions: {
sourceType: 'module',
},
plugins: [
'googleappsscript',
'@typescript-eslint',
'prettier',
],
extends: [
'standard',
'prettier',
'prettier/@typescript-eslint',
],
rules: { // example
'prettier/prettier': ['error', {
useTabs: false,
}],
'no-var': 'error',
'@typescript-eslint/camelcase': 'error'
}
}

ちなみに僕の場合、PrettierとESLintともにもっと細かくルール設定しています。
そして、Husky経由でGitのcommit時に自動でeslint --fixがかかるようになっています。
その辺のことは以前書いた記事をご参照ください。

LintとFormatをGitのコミット時に自動でかける方法 - Trial and Spiral

型定義の導入

これでようやく環境が整った! と思いきやまだあるんです。そうです型定義です。
ありがたいことに公式でGAS関数の型定義が用意されているのでサクっと入れます。

yarn add --dev @types/google-apps-script

これでGASの関数に関してはばっちり型サポートが有効になります。

GAS用ライブラリの型定義

GAS用ライブラリを導入した場合、多くはグローバル関数として使えるようになります。しかしローカルで開発するときはそんなことはわからないので、そんな関数の型は定義されてないぜ、っていう警告が出ます。
それを回避するためにindex.d.tsファイルを作って、例えばこんな感じに書きます。

index.d.ts
declare const Moment: {
moment(arg?: any): any
}
declare const Underscore: {
load(): any
}

これは僕の中でまだ上手くいってない部分で苦肉の策です。MomentもUnderscoreも同名のJSライブラリが元になっていてすでに型定義ファイルが用意されています。使い方がちょっとだけ違うのでそこを上手く吸収しつつ、型定義をうまく流用できたらいいなあと思っています。

どなたか解決方法があったら教えていただけると嬉しいです。

そんな感じで長くなりましたが環境構築ひとまず完了です。
次回は実装編を書けたらいいなぁ。

Git 初回コミットのメッセージをちゃんと決めてみる作戦

  1. 1. なんで決めるか
  2. 2. 一般的にどうか
    1. 2.1. 調べてみた
  3. 3. 僕はinitに決めた
  4. 4. ちなみにrebaseはできる

新しいことをいろいろやろうとすると、それがSandboxであれgit initすることはそこそこあると思う。で、毎度毎度うっすら「初回のコミットメッセージって何か決まりあるんかな」と思うけど、まあわかればいいか、と思って適当にやるっていう感じだった。今回はそれをちゃんの決めてみようというお話。

なんで決めるか

僕の行動原理として「小さなことでも何度か考えるなら論理的にルールを決めると楽」という実感がある。
これはインデントがどうとか、コーディングフォーマットにも通じるんだけど、要は本質じゃないものからのノイズを減らして本質にフォーカスしやすくする、という戦略のつもり。
余談だけど僕がSCSS嫌いでSASS好きなのもそういう理由だったり(Stylusはもっと好き)。

なんかカッコつけたけど、毎回3秒でも悩みたくないから決めちゃっておきたい、でも自分の中だけにでも納得のいく論理的理由が必要、という面倒な自分を御したいだけな話。ちょっと最近いろいろと忙し気味なので、そういう時はこういう簡単なことをサクっと処理する時間にあてていきたい所存。

一般的にどうか

そもそも絶対こうじゃなきゃいけない、というものはない様子。ならばまず最初に狙うべきは「一番多い」というところ。 Gitは複数人で扱う前提とすれば「誰もが迷わずそれが初回コミットであることを認識できる」というのが必須条件になってくるはずで。

そうすると良く見かけるのはfirst commitinitial commitのどちらかだろうと思う。ちなみに今までの僕はinitial commitを使ってきてる。
これは予想だけど、僕も含めGitを初めて扱い始めたころのチュートリアル的なものに影響される人が多いんだと思う。

もう1つ日本語メインでやっている人の場合は「初回コミット」というのも見かける気がする。考慮すべきはまあこのあたりかなぁ。

調べてみた

ちょっと面白い記事を見つけたので紹介したい。

すごい簡単に説明すると、スクリプト書いてある分野のGitHubのリポジトリの最初のコミットメッセージを集計してみた、的な感じ。

これを見る限りではやはりfirst commitinitial commitが郡を抜いて多い。ついでadd readmeのようで、これはとりあえず最初にreadmeだけアップした、みたいな感じなのだろう。
タイポや省略形もあるのでザっと見た感じで分けると

  • first派(1st commit, first commiitなど)
  • initial派(init, initial, initial commitなど)
  • add派(add files, add readme, create readme, など雑多)

の三種類に大別できるかなーって感じ。

注意すべきは対象がrOpenSciのものだけみたいなので、少し偏りがある可能性も否めない。

僕はinitに決めた

まあ「最初のコミットだよ」ってわかればなんでも良さそう。先程の例に習って僕もスクリプト回してみようかと思ったけど、結局やらずに決めてしまった。

僕はinitで行こうと思う。

理由として、

  • commitという情報はそれがコミットメッセージである以上、書かなくてもわかるので省略
  • Gitの最初のコマンドは$ git initですので
  • 正直わりとどうでもよくなったので短かくてわかりやすいのでいいやってなった

という理由。
これでもう初回のコミット時にメッセージどうしようか思いを馳せることはなくなった、1リポジトリあたり3秒ぐらいの時間的コストをカット、同時にその一瞬思考をそっちにまわす脳内ワーキングメモリコストもカット(わりと無視できる程度な差なのは否めないw)

ちなみにrebaseはできる

今回初回コミットについて調べる過程でメッセージとは違う軸の話として、

最初のコミットは前コミットが存在しないためrebaseができない、だから初回コミットはあえて空コミットにする

みたいな話を見かけたけど、よくよく調べてみると

$ git rebase -i --root`

とか--rootオプションで一番最初のコミットを含めて修正できるし、実際試したら出来たのでこれは採用しなかった。

ただ、最初を空コミットにしてcreate this repositoryとかにしてもアリかなぁとも思った。いやいややっぱりナシで、僕はもうinitに決めたんだ、迷わないんだ!

UXデザインのペーパープロトタイプの講座を受けにいってきました

  1. 1. イベント概要
  2. 2. 参加動機
  3. 3. 講義について
  4. 4. 前半:ペーパープロトタイピングについて
  5. 5. 後半:ペーパープロトタイピング体験
  6. 6. まとめ

昨日、ユーリカ株式会社さんが催行しているUXトライアウト・2時間で学ぶペーパープロトタイプに、前回と同じくブログ書く枠として応募したところ抽選に当たったので参加させていただいたのでそのレポートです。

今回もまた詳細な内容は講義を受けたほうがより正しい内容なはずなので、主には概要と感想です。

イベント概要

UXデザイン会社のユーリカ株式会社さんで定期的に行なわれる「UXトライアウト」と題したコースがあって、基礎知識からUXデザインで行なわれる各行程ごとに2時間のワークショップ。どんなものがあるかはTECH PLAYのユーリカ株式会社|UXデザインで売れるモノづくりを応援しますのイベント・技術情報 - TECH PLAY[テックプレイ]で見ると良いと思います。

ちなみに通常は有料の講義だけどブログ書く枠は抽選枠ですが無料参加で募集しているようです。

参加動機

前回も書いたけど、良いものを作るためのUXデザインの話まで自分としても注力していきたいので。その技術を業務で活かしたいのはもちろんなんだけど、僕は個人開発も行なってるので個人でやる場合は全部を自分でやらなきゃいけない。

実は応募自体は前回のものと同時につづけざまにしたので前回と動機に違いはないものの、UXデザインの具体的な手法として例えばユーザーインタビューとかあるけど、まず個人レベルで手がつけやすそうなのはペーパープロトタイピングかなーと思っての応募。

講義について

前半は、ペーパープロトタイピングってどのようなものか、どうやってやるのか、やるための便利なツール(アプリなど)の紹介という感じ。
後半は実際にワークショップとしてやってみて、レビューしてみて、という感じの大きくは2部構成。

前半:ペーパープロトタイピングについて

まず話として、「へー」と思ったのが「評価」することを前提として作るということ。僕は何かをつくるときそれがWebでも趣味のレザークラフトでも基本的にまずラフスケッチをするんだけど、それは頭にあるものをちょっと具体化する程度のもので書き散らすことが多い。

工程としてそれも必要かもしれないけど、作るときは気分が乗ればガーっとコーディングから始めてしまう。だけどプロトタイプはちゃんと評価する、というのが違うんだなぁと思った。まあその結果が作ってる途中で「あ、これこうだとダメじゃん」とかって手戻りが発生するわけなんだけど。

で、アプリやWebの開発の場合、ペーパープロトタイピングでは全ての画面や動きなどをできるかぎり手書きでOKなので用意して、実際の操作を模して、紙を変えたり乗せたりしてシミュレーションする感じで評価するとのこと。

これは欠点として紹介されてたけど、その紙の差し替えは非常に面倒だという問題。なので例えば写真にとってデジタルツールと組み合わせてやると良いということでツールの紹介があった。

個人的にはここでFigmaの名前があがらなかったのが不思議だったけど、Sketchの名前も出なかったので、実際この講座は初心者向けなために、きっとそういうデザイナー寄りのツールではなくてまず使うための前提知識や技能が要求されないものをオススメしてくれたんだろうと思う。

ちょっと残念だったのは思ったよりこのツールの使いかたや類似ツールの説明などの話のボリュームを減らして、実際のペーパープロトタイピングの具体的なやり方とか気をつけること、守るべきルールとかをもうちょっと教えてほしかったなぁという気がしなくもない。アプリの使いかたはアプリが違えば変わってしまうので。もちろん僕は個人的にFigmaとかでやるだろうなぁ、と思ったという背景もあるけど。

後半:ペーパープロトタイピング体験

そんな説明があった後にじゃあ実際体験してみようということで出たお題は「Instagramを記憶、または想像だけで再現してみよう」というお題。

まず僕が作ったのはこんな感じ

実習

日頃から個人開発とかやるときに画面構成を書いたりしてるのと、業務でも仕様書的なものを見てるのでわりと想像はつきやすかった。

やって思ったのはInstagramはあまり使うほうではないけど、それでも迷うことなく使えている。かといってどこにどのような要素があったかというのは正確に把握してるわけでなく、なんとかそれなりに書けたのも、よくあるUIならここに置くだろうという推測で描いた要素のほうが多かった。

実際に簡易的な取り込みアプリをつかって、操作を模してレビューしてもらったりした。決定とか削除ボタンとか付けわすれた。あとは、何がどこにあるべきか、って思ったよりは難しかった。逆に面白かったのは、自分でちゃんと投稿されたかどうかのモーダルを想像できたり、「ここで多分GETのAPI叩いて、Arrayで返ってくるから」と想像してたのは無意識に発露したサーバーサイドエンジニア目線なんだろうなぁと感じて面白かった。

実際に体験してみるまでは、いきなりSketchとかFigmaとかのツールでやったほうが早くない? と思ったけどそうではなくって、触ることを意識したり、紙の状態でもいいからこれを触ったらこう反応して、というインタラクティブな動きをシミュレートすることで不足を炙りだすのにすごく役に立つと実感した。

なんというか「早く失敗する」というか。最初から最良のアウトプットを出そうとするんじゃなくて手書きでパパーっと描いてシミュレートする、過不足を早い段階で炙りだしてから問題なさそうなら次にもっとしっかりしたものをデジタルで作る、みたいな工程を組んだほうが結果的に早そう。

ただしそれが絶対というわけではなく、同じような画面や同じような部品のものは、手書きだと逆にコンポーネント化して使い回しとかできずにイチイチ書かなきゃいけないからかったるいなーとも思った。だからそういうところ上手く簡略化してやるのが良い落しどころなのかもなぁ。

まとめ

こうしてやってみたらやっぱり重要な工程だった。だけどこれだけやればじゃあUIに関してはバッチリかいうとそうではなく、使う人がどのような層なのかというコンテキストで最適な配置や表現する文言や使う単語、アイコンも変わってくる。だから他のユーザーインタビューやペルソナを想定したり、カスタマージャーニーマップも必要になってくるんだと思う。

2時間ではもちろん時間が足りないのでどうしても「お試し体験」的学習になるけど、それでも今回もなかなか良い学びでした。やっぱり何ごともトライして試して手を動かさないと。他の人はどうかわからないけど、とりあえず手をつける、体験してみる、が僕が僕を活かせる勉強のやりかただと思ってるし、そこを躊躇しないのが僕の強みだと思ってるので。

今回も今や便利ツールがいっぱいあるのに手書きでやることの意義とか効果とかも実感できたので良かった。今も職場で小さいホワイトボードが欠かせないように、デザインだけじゃなくて、シーケンスやら分岐やら、設計もわりと手で描いてみて考えるタイプなので、手書きを活かすアイデアが1つ足されたような感じ。

それと同時に余裕があれば(といってるうちはいつまでたってもそんな日は訪れないんだけど)Figmaとかももっと触っていきたいと思った。

今後もUX系の講座には参加したいと思うものの、今はそれが本業ではないのでいったんはこれくらいにして、紹介された本やUIに関するガイドラインとかをまず読むところからひとつづつ一歩づつ進むことにしよう。粛々と。

コンポーネント時代のCSSの命名ルールを考えてみよう

  1. 1. ScopedなCSSとは
  2. 2. デファクトスタンダードなBEM
  3. 3. 僕はSMACSSが好き
  4. 4. オレオレルールを模索する
  5. 5. まとめ

このブログはHexoというNode.js系の静的サイトジェネレータで作ってる。テーマはイチからフルスクラッチで自分で作った。でも自分で作ったがゆえにまだ手のゆき届いてないところがあったり。そんなこんなで久々にテーマをどう作ってたってところから見なおしてたり。

そんなことから、そういえば以前はBEMやらFLOCSSだったり、SMACSSのルールに基づいてCSSを書いてたなあ、と思った。一方、React, Angular, Vueの三大巨頭が牽引するコンポーネント時代に突入してきた今、CSSの効果範囲はScopedにものが主流になってきている。ScopedなCSSはそれに適したまた別の命名ルールが存在するのでは、と思って考えてみたという話。

ScopedなCSSとは

まずScopedなCSSについて簡単に説明したい。
そもそもScopedなCSSというのはJS系フレームワーク産の発想ではなくて、一時期はちゃんとFirefoxにも実装されたようにCSSそのもので提案された考えかた。

CSSは名前のとおりカスケーディングに処理されているけれど、カスケーディングがゆえに乱暴に言えば全てがグローバルに宣言されていると同じようなもので、そこから、あるDOMの中でだけに絞って作用させたい用途としてScopedが生まれたんだと思う(この辺あいまいです……)

残念ながらそれは正式に採用されることはなくなったようだけど、WebComponentよりも先駆けてコンポーネント指向の急先鋒となったReact, Angular, Vueには実装の形は違えど、各コンポーネント内だけでしか作用しないCSSの書き方がある。それを今回は便宜上「ScopedなCSS」と呼んでいる。

デファクトスタンダードなBEM

さて、Scopedじゃない時代、人は常にCSSの影響範囲と戦ってきた。基本的にはそれぞれにクラスをちゃんと指定して、クラス名の命名規則とつけかたで頑張りましょうという戦略。

そこで生まれたのがBEM(Mind Bemding)という手法。block__element--modifierという命名規則で、親子関係がしっかりしているのが特徴。OOCSS(オブジェクト指向CSS)としても構造がわかりやすく、今やCSS命名規則のデファクトスタンダードと言っても過言ではなさそう。

僕はSMACSSが好き

BEMもSMACSSもどちらもある単位ごとに分けて管理しよう、って概念はかなり近い。個人的にはBEMよりはSMACSSのほうがわかりやすい気がする。その反面、Mに相当するモジュールの自由度が高くて悩むこともしばしばある。でもそれはBEMにしてみてもブロックでの区切りかたに悩むのと同じようなもので。

SMACSSが大きくBEMと違うのは、ステート(状態)をマルチクラスとして宣言するところ。BEMの場合で言えばModifierに相当し、例えば同じように書くとしたらBEMなら.module--stateと指定してたのをSMACSSなら.module.is-stateというような感じ。

個人的にはこちらのほうがCSSの特性を考えると、状態の変化を上手くあつかうには適していると思っているのでこっちのほうが好きだ。

オレオレルールを模索する

じゃあコンポーネント指向になった構造でScoped CSSになったとき、どうするのが良さそうか、っていう話。

AtomicDesign的な思想をベースとすると、コンポーネントの単位はその「責務」によって分割されるべきで、これがCSSのデザインのブロックやモジュールとは非常に似つつも完全に同一でないのでちょっと混乱しやすい。

まず、SMACSSで言うようなレイアウトのプレフィックスはいらないくなってくるはず。つけたいなら付けてもいいけど、Scopedである以上、レイアウトを扱う部分とモジュールの部分は別コンポーネントになるべきだ。もし必要になるのであったらそれはCSSの話じゃなくてコンポーネントを責務にわけた設計にしたほうが良い。

コンポーネント内でのクラス名はBEM的なのが良さそう。BEMのツライところとして、1つのまとまりだけどHTMLの構造上Elementが多層になったりするとBEMのルールだけではなかなかやりづらいようなことがある。BEEMとかにしたいときとかあるはず。BEMの規則にのっとるとこれはダメなので別のブロックとしてとらえてまた別の命名を考える、となるんだろう。けどコンポーネント指向の場合、そんなに多層になるのであればそもそもコンポーネントの切りかたが悪そうな気もしてくる。

BEMで言うモディファイア、SMACSSで言うステートは、SMACSS流にのっとってis-stateとかhas-stateisもしくはhasプレフィックスをつけて、変化するところだけを指定する。これはその状態が変化したときには、SMACSS的にマルチクラス的に指定してクラスを付けかえるほうがやりやすい。hasも加えたのは、isだけだと意味がおかしいことがあるので。

その結果、僕が「これでいってみよう!」と思ったのは、Scopedなコンポーネント内だけで

.some_block--some_element.is-state

というような書きかた。

説明すると

  • 複数語の場合、単語の区切りは_(アンダースコア1つ)
  • 階層的になる場合、--(ハイフン2つ)でつなげる
  • 状態の変化した場合の指定はis-もしくはhas-というプレフィックスのクラスを足す

ここでBEMに慣れ親しみすぎてると「おいおいハイフンとアンダースコアの使い方が変じゃない?」と思うかもしれない。僕がこう定めてみたのにはちゃんと理由があって、文字の選択をする場合などで

  • ハイフンで区切られた単語はハイフンを挟んで別の単語として認識される
  • アンダースコアで区切られた単語は1語として認識される

という特徴があるため。試しに上のsome_blockとかsome_elementとかをダブルクリックとかで選択してみてほしい。

ブロックと要素の区切りがハイフン2つにしたのは、BEMがやってるように、前後は別のまとまりというのを認識しやすくするため。単語の区切りが1つはなのはそれとの差別化。これでBEMに慣れすぎていても、blockとelementは違うくくりだな、と混乱しないようになってると思う。

まとめ

ScopedなCSSをメインで書くようになってから、命名ルールすら適当でも問題なくできちゃうぐらい便利で、今までなあなあで来てしまってた。それでもやっぱりルールは欲しいもので、あっちではBEMっぽく書いてこっちではSMACSSっぽく書いて、みたいにやってしまってたのでなんかずっと喉につかえた小骨のように気持ちわるかった。

単純な静的なページでもReact, Angular, Vueなどが使われはじめてみんなScopedなCSSで書けるようになってきていて最近は以前ほどOOCSS派生のルールみたいなものを聞かなくなってた気がする。それでも今回、一応自分の中では「こういうルールで行く!」と思えるようなものを決めれたのはなかなか良かったと思う。

他のみなさんはこのコンポーネント時代のCSS命名をどのようなルールでやってるか凄く興味があるなぁ。

UXデザインの基礎知識の講義を受けにいってきました

  1. 1. イベント概要
  2. 2. 参加動機
  3. 3. 講義について
    1. 3.1. UXデザインとは
    2. 3.2. UXをデザインする方法
    3. 3.3. UXデザインの手法の解説
  4. 4. 感想

昨日、ユーリカ株式会社が催行しているUXトライアウト・2時間で学ぶUXデザインの基礎知識にブログ書く枠として参加させていただいたのでそのレポートです。

詳細な内容は講義を受けたほうがより正しい内容なはずなので、主には概要と感想です。

イベント概要

UXデザイン会社のユーリカ株式会社さんで定期的に行なわれる「UXトライアウト」と題したコースがあって、基礎知識からUXデザインで行なわれる各行程ごとに2時間のワークショップ。どんなものがあるかはTECH PLAYのユーリカ株式会社|UXデザインで売れるモノづくりを応援しますのイベント・技術情報 - TECH PLAY[テックプレイ]で見ると良さそう。

ちなみに通常は有料の講義だけどブログ書く枠は抽選枠ですが無料参加で募集しているようです。

参加動機

常々良いものづくりをしたい、と思ってるのは開発者はみんなそうだと思うんだけどじゃあその「良いもの」を狙うにはUXデザインしないとね、と思ってたのが発端。

以前からUXデザインに興味があったけど、聞いたことあるレベルだったりぼんやりなんとなくレベルの知識だったので具体的にどうやるんだろう、ということをまず知りにいきたかった。

先に結論から言えば、「これは、(デジタルアナログ問わず)ものづくりをする人にとって必修でしょ」と思えるぐらい良かった。

講義について

今回の「UXトライアウト・2時間で学ぶUXデザインの基礎知識」というコースは他のコースは基本的にワークショップらしいのだけど、今回に限っては基礎知識なので基本的には座学。

大きくわけて

  • UXデザインとは
  • UXをデザインする方法
  • UXデザインの手法の解説

の3部構成。

UXデザインとは

まず講師の森山さんは強く強く「UI/UX」と良く言われるが、これらは全く別モノで関係がない。ということを強調しておられた。 これには僕も全く同意でそこここで並記されて同一のくくりで語られることはもちろん、混同してる人も多い印象を受けてた。

そもそも「インタフェース」と「エクスペリエンス」は言葉として全く別で、僕個人では混同してるのを見ると「略語の意味すら調べない、自分の使う言葉に無責任で無頓着な人」という印象すら受ける。

つまりUXはエクスペリエンス、ユーザーの体験をデザインすることであって、UIは体験に影響を与えるほんの一要素でしかない。ということ。最初にこれを強調して話されてたのが良かった。以前なんかのセミナーでUI/UXについて語るようなものに参加したこともあるけど、そういう話がなかったので。

常々なんで別モノが並記されてるんだろう、と思っていたけど講師曰く「企業の採用ページなどで「UI/UXデザイナー」と書かれることが多く、そこから一般化してしまった」とのこと。
これにはなるほど、と思った。確かにUIデザインとUXデザインは兼任できるだろう。すべきかどうかは別として。また面白い言い方だとUXデザイナーというのはプロダクトのUXに関する監督だと。

UIはUXを左右するほんの1要素なだけ。

UXをデザインする方法

UXとは要は、

  • いいね! と思う気持ち
  • その気持ちに至るまでの過程
  • その気持ちを動機とする行動

の全て、というのをふまえたうえで「人の気持ちは設計できないけど、過程は設計できる」という言葉が印象的だった。この一言でいろんなものが腑に落ちた。ありがとうございます!

ここではその過程についてどんなものがあるか、という話を受けたんだけどその中でも「期待外れはUX的にマイナスなので期待外れを興さないように適切な予想を与える」というのが印象を受けた。ただ「これ良いよ!」って思わせればいいもんじゃないんだな、と。

で、いろんな方法の1つとしてUIデザインパターンとかガイドラインとかあるけど、それだけだと足りないので、ISO 9241-210(人間中心設計プロセス)とUXデザイン手法の、ユーザー調査、ユーザーモデリング、理想シナリオ、プロトタイピング、UX評価の説明。

UXデザインに関する手法がISOに定められてるのは全く知らなかった。それで良く話に聞くペルソナやらシナリオとかカスタマージャーニーマップとかっていうのはこの行程の中の1つ。

UXデザインの手法の解説

ここは前章で紹介されたUXデザインのプロセスについてあるサンプルにそって、1つづつ説明を受けた。例えば、インタビューはどのようなもので、それから次の行程がこうできてきて、ペルソナ作りに移行して、というような感じ。

簡単なサンプルではあるものの十分にその過程と様子とやりかたの概要は掴めて非常に有意義な説明だった。おお、なるほど、こうやるのね、と具体的にイメージできたような。

で、やっぱりUIデザインは中に出てくる。プロトタイプの作成のところで。だからやっぱりUIはUXに影響を与えるほんの1要素以上ではない、ということ。

感想

前半のUXとUIは別物で、こういうもの。っていう話、UXデザインってこういうこと、みたいな話まではだいたい知識として持っていた。そういう説明をちゃんとされたことが、けっこう自分の中で有意義で、一見持ってる知識を再度説明されるって無駄なように見れるけど、自分の理解の確認、言語されてよりクリアな認識になる、という意味は大きかった。

後半のUXのデザインの技法については、エンジニアとしてプランナーさんとかディレクターさんとかと一緒に仕事しているわけだけど、彼らはちゃんとそこまでやってるのかな、という印象。
正直、会社としてこういうセミナーや講座に授業料払ってでも行かせるべきだろうなあ、と思うし、行かしてくれないなら自分から行くべきだな、とも。エンジニアは進んで勉強するけど、エンジニア以外の職種の人が勉強会とかセミナーとか積極的に行くって話はあまり聞かない。

冒頭でも言ったけど、UXにかかわるならこのあたりまでは必修じゃないかな、と思う。

一方個人的な興味に立ち返ってみれば、StrengthFinder調べで僕の資質に「回復志向」というのがあって、これを自覚してから感じるようになったのが「僕は本来の価値を十全に発揮できない状態が嫌い」らしい。

別の見方では貧乏性というか、もったいないというか。なので「モノ自体はいい」とか、上手く機能してなくて改善する余地がある、とかそんな状態が大嫌いらしい。その価値の最大化する手段としてUXデザイン技法が使えそうだなぁと強く思った。

なにもプロダクトに限ったことじゃなくて例えばチームビルディングに関しても、チームメンバーはみんな良いところあるのに、いろいろやり方が良くなくって価値を最大化できてない、とか。それをUXデザイン技法を用いて良い方向に持っていくことも可能だろう。

あとはゲーム。ゲームってプレイヤーに楽しませるのが目的なんだけど、そこには凄く細かくいろんな心理状態への働きかけがある。ボードゲームとかやると特に顕著で、ジレンマを上手く発生させたり、とかね。

UXにつながる心理状態を作り出すための過程のデザイン、というのはかなり広範囲に応用の効くものだろうだと感じた。

そんなわけでUXデザインの興味と勉強は僕の中でもうちょっとプライオリティ上げてもいいな、と感じた。まだまだエンジニアとしてレベルアップしたいし、エンジニアとしての勉強もやりたいもの全部は難しくて効率的に適切に捨選択していかないといけない状況だけど。

これまでにも書いたけど、デジタルプロダクトだけでなくアナログでもUXデザイン技法は変わらず使えるので、ものづくりに携わる人みんな基礎ぐらいは知って損はないです。
満足度すごく高い講座でした。また別のクラスも是非参加してみたい。

LintとFormatをGitのコミット時に自動でかける方法

  1. 1. 使うもの
    1. 1.1. Husky
    2. 1.2. lint-staged
  2. 2. インストール
  3. 3. 設定
    1. 3.1. まずhuskyの設定
    2. 3.2. lint-stagedの設定
  4. 4. おまけとまとめ

前回、LintとFormatをかけるのはもちろんなんだけど、なんでGitHookのタイミングにしたかって話を書いた。今回はそれの具体的な方法を書いていこうと思う。

ちなみに前回書いたやつ。

使うもの

まず使うNPMのライブラリを使うので、Node.jsを用意してください。これmacならbrewでyarnを入れてもいいし、僕はanyenvを経由してndenvを使ってる。いろんなやり方があるし、それぞれ利点が違うので自分にあった入れ方を推奨。

それで使うライブラリなんだけど

  • husky
  • lint-staged

の2つ。以下で簡単に紹介しよう。

Husky

huskyはGitHookをプロジェクト単位で設定できるようにするツール。
GitHookの設定は通常だと{project root}/.git/hooks/配下にある。.git以下は通常ではリポジトリに含まれないので共有されない、つまりhookを共有したり強制したりできない。

だから、husky経由で共有できるところで設定できるようにする、というのがhuskyの役割。どうやらhuskyを入れたときにGit hookをhusky経由で動くように入れかえてるっぽい。

lint-staged

lint-stagedはgit addした対象に対して特定のコマンドを走らせるもの。READMEにもあるとおりhuskyと合わせて使うのがオススメとされている。ちなみに以前はhusky以外にもpre-commitをやり方やいろいろあった。あと、名前はlint-stagedだけどやることはstagingされたコミット前のものに対して何かをするのでlint以外にも使える。

ちなみに昨年前半あたりまでずーっとハンク(git add -p)したファイルの対応する方法に関してissueで議論されていたが、昨年中頃にlint-stagedがアルファ版を経て正式に対応した。個人的にハンクはかなり使うのでずっと動向を追っていたし、これが解消されたからプロジェクトに導入したし、紹介するに相なりました。

インストール

npmに慣れてる人には言うまでもないだろうけど

$ yarn add -D husky lint-staged
# or npm install -D husky lint-staged

でOK。

設定

package.jsonに設定を書いていく。ちなみに別ファイルに分けることもできるけど、そう複雑で長い設定でもなく、huskyとlint-staged両方とも連続した設定になるし、package.jsonのscriptともかかわることもあるので個人的にはpackage.jsonだけでやっちゃうのが良いと思ってる。

まずhuskyの設定

以下を追加

package.json
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},

要はhuskyの設定を、hooksのpre-commitにlint-stagedコマンドをするよ、という設定。
ここではpre-commitだけだけどもちろん他のhookも同様に書くことができる。詳しくはhuskyのREADME参照。

lint-stagedの設定

同様にlint-stagedの設定もpackage.jsonに書く。ここはどのようなファイルにどのようなlintをするかので一例として

package.json
"lint-staged": {
"*.{js,ts,vue}": [
"eslint --fix",
"git add"
]
},

みたいに設定する。
lint-staged直下の設定で対象のファイルのglobパターンを書く。例えば上の例だったらGitのStageにある拡張子がjs,ts,vueのものにeslint --fixがかかる。これで自動で修正された結果のファイルが再度addされて、問題なければcommitされる。

もちろん、lintの結果エラーが返ったときはcommitされない。意図的にpre-commitフックを避けない、という前提のもとであればコミットされたものは全てプロジェクトで設定されたLintのルールにパスしていることが担保される。

で、もちろんファイル名の条件にしたがってコマンドを走らせるだけなので、

package.json
"lint-staged": {
"*.{js,vue,ts}": [
"eslint --fix",
"git add"
],
"(*.rb|*.rabl|Gemfile)": [
"bundle exec rubocop --auto-correct --fail-level E",
"git add"
]
},

みたいにやればこの例で言えばJS系だけでなくRubyのファイルにRubocop(Ruby用のLinter兼Formatter)をかけるようにもできる。

ちなみにJS系のformatterとしてprettierがあるけど、eslintのルールとバッティングするところもあるので、eslintにpluginを噛ませてeslintの中でprettierによるformatするのがお勧め。

おまけとまとめ

あとは以前に紹介したcommitizenもNPMなので一緒に使うのも簡単で、そうするとコミットメッセージも綺麗、コミット内容もキレイ、という素敵なコミットができる。

と書いてきたけど、やってることはいろんなところで紹介されてるしそんな難しいことじゃない。
でもNPMがフロントエンド特化傾向にあるため、Node.js系をふだん使ってない人には有用であればうれしいなぁ。特にRailsはWebpackerやらYarnを採用したこともあって相性は悪くないと思う。

途中でもちょっと触れたけどこのGitのハンクに対応したこともあって、この仕組みを業務でも使ってみたけど上手くいってますのでけっこうオススメしますよ。

LintとFormatをGitHook時にかけてる理由

  1. 1. いつかけるか
    1. 1.1. Save時
    2. 1.2. GitHookにひっかける
    3. 1.3. Pull Request時にCIで回す
  2. 2. もうひとつの目的
  3. 3. 実践

LinterとFormatterをかけないコーディングはツラくて個人的にはちょっと悲しくなるんだけど、問題はどのタイミングでやるかってこと。個人的にやっていたものを昨年なかごろから業務にも取り入れてみてそこそこ上手く回っているので書き残しておきたい。

いつかけるか

LinterとFormatterをかけるとしたらいつがいいのかいろいろ考えて、結論から先に言えばGit commit時にしている。なんでそう結論づけたかっていう話の比較を交えてご紹介したい。

Save時

一番頻繁にかかる一例としてファイルの保存時。例えばVSCodeなんかではFixOnSaveとかって設定があるようにわりとメジャーだと思う。

Saveするときにかかるので一番頻繁だし、適当に書いてもガっとキレイにFormatは効くし、変なコードはすぐに警告が出る。良い。

でも残念ながらできるかどうかははエディタ頼みになってしまう。独りで開発しているときは十分かもしれないけど、みんな違うエディタだったり対応できないエディタの使用者がいたら?

例えもし開発者それぞれが使うエディタで全部対応できたとしても、エディタごとに設定もプラグインとかも違ってくるのでどうしてもノウハウが属人化してしまう。

一番大事なのは自分以外も加わるとしたら強制できないのであまり有効でないところ。ルールを適用するならそれは守られなければ意味がない。

GitHookにひっかける

GitにはGitHookという機能があって、commit時やpush時に設定したスクリプトを回すことができる。最初に言ったようにこのフックにひっかけてpre-commit時にLinterとFormatterをかける運用にしている。

理由はcommitをしないことには開発は進められないし、エディタがなんであろうと強制できる。そしてローカル上でエラーが出るのでそのcommitする開発者が自分でエラー箇所を修正することになる。また最悪どうしようもないときは--no-verifyオプションをつけることで一時的にGit Hookを飛ばすこともできる。

ちなみにpre-pushも検討してみたけど、push時に弾かれたり修正が入ることでコミットログがエラーやコーディングスタイルの修正だけになったりして、それは別コミットにすべきじゃないと思ったのでpre-commitにした。

Pull Request時にCIで回す

他の候補としてPull Request時にCI等の外部サービス経由で回すことももちろん検討した。これも結局はpre-pushと同じようにコミットをキチンと整理したいこと、その後のマージ戦略まで影響するのがちょっと面倒で見送った。

ただし方法としては一番、開発環境に依存しない方法だし悪くはないと思う。pre-commitにしろpre-pushにしろ、CIにしろ、ポイントとしては

  1. Lintに通ってないコードを採用しない(できない)。
  2. Formatterのルールにのっとってないコードを紛れこまさない
  3. 1と2を共同開発者全員で共有する

というのが前提として守りたいルールだった。

もうひとつの目的

なし崩し的にチームリーダー的なポジションになって後輩を抱えるにことになったけど、なにもイチから教えることはなくて「こういうコードがいいよね」っていうのはLinterやFormatterに助けてもらうことにした。

なにより僕がレビューコメントや口頭で「こういうコードがいいよ」っていうより、ルールの説明のドキュメントのほうがよっぽど説得力がある。

まずチームにJoinすることになったときにルールを確認してもらって、できればその時になんでそういうルールを設定してあるかもコメント等で共有する。そしてそのルールに納得してもらうようにした。反論は出なかったものの今でも合わないルールがあったら変えるからいつでも相談して欲しいとは伝えてある。

そうすることで例えばLinterではうっかり使用されない変数、到達しえない分岐、デバッグ用のコードなど紛れこんだままだったり、同じ結果だとしてもよりリーダーブルな書き方だったり、そういったことがPull Requestに紛れこまないことによってレビューの時間コストも抑えれるし、エラーが出たら自身でちゃんとルールを参照して修正してもらうようにしてる。そうすることで自身で徐々により良いコードを書けるようになってもらう作戦。

またFormatをキチっとやるのことも僕は大事だと思っていてインデントが不揃いだったり、なんか感覚的に気持ち悪いっていうことだけじゃなく、コーディングスタイルを統一することで読みやすくして、本質じゃないノイズを極力カットすることで本質にフォーカスしやすくするのが狙い。

この目的にあたって注意したのは「ルールは聖域、無視しちゃダメ」ということ。もちろんキビしすぎるルールは時に枷となって開発スピードを鈍化させたりもするんだけど、そういう場合もキチっと直すことを意識した。なんども苦労するようであればそれはルール自体を変更したり緩めたりすることで対応する。

これはLinterのルールは割れ窓理論的に悪化しやすいと思っていて「ああ、このルールはまあ無視してもいいよ」みたいにしてしまうと次第にどんどん広がっていき、最終的にはルールは守られず、無いもの同然になってしまう。その経験が僕にはある。だから「ルールは聖域、無視したいのであればルールの変更を提案しよう」として運用して、事実上手くいってる。

実践

じゃあpre-commit時にLinterとFormatterをかけるための具体的な方法なんだけど、それはちょっと次回に回したいと思います。使ってる言語と環境にも寄るんだけど、僕の主戦場がRubyとJS(TS)なのでそれら限定になってしまう。とはいえフックさせて回すのはNPMライブラリだけでやってるので他の言語のプロジェクトでもNPMを同時に使えば実現できそう。

そんなhuskylint-stagedを使った具体的な設定はまた次回。

追記
書きました。

ここ1年ちょっとで僕が作ったプロダクト

  1. 1. Pentazemin
  2. 2. MHW-cheatsheet
  3. 3. YANTAN
  4. 4. cz-conventional-changelog-ja
  5. 5. その他
  6. 6. 所感とこれから

いよいよ2018年も終わりそうで。今日は職場の大掃除があってようやく年末感を味わいはじめた。せっかくなので今年に作ったもの達を振りかえってみたいと思う。ちなみに開発系限定で。というのも開発系にフルコミットしたからなのか、単に気が向かなかったのかレザークラフトとか物体の物作りは全然してない。

Pentazemin

いわゆるポモドーロテクニックを利用したタスク管理アプリ。どっちかというとタイムマネジメントの側面が強い。気になった人はリンク先を見ていただけると嬉しいです。

時間的には去年、2017年の終わりごろにリリースしたアプリなんだけど、当時はまだVue.jsもそこまで人気じゃなくNuxt.jsのver1でさえベータ版だった。そう思うと2018年のそのあたりの速度って凄かったなぁ。

こういうアプリが欲しいなぁと思いたって、ちょうど今Vue.jsやってみたし、おっElectronも勉強しながらやったら面白いんじゃない? と思って作った。そしてこの時にガッツリVue.jsに触れて苦戦しながらもちゃんとリリースまで持ってったのが今の僕のVue.jsの基礎力となってその結果素晴しく力がついた。

作ってできたーじゃなくて、使ってもらうために紹介ページを作ったりして、いくつかのブログで紹介されたり、外からお声がかかるきっかけになった。開発力だけじゃなくて作る以外のことも含めて僕の2018年を支えてくれたプロダクトでした。

2018年いろいろ作ってきてレベルアップできた感があるので、今の技術でちゃんと一新したい。

MHW-cheatsheet

年の始めにMonsterHunter Worldというゲームが出て、夫婦ともにガッツリハマって。簡単に説明するとみんなで協力しながら大きなモンスターを狩る、みたいなゲーム。で、モンスターには属性や攻撃部位による弱点があってなかなか複雑。

ネットを見てたら早見表みたいなのが凄くバズってましてね。絶賛されてるんだけど、個人的に「おいおいまだ見やすくできるだろ」という思いが膨らんで、よっしゃいっちょ作ったるか、せっかくだからVue.jsでPWAやってみよって作った(とはいえ、最初に画像でもなんでも形にした先人達には敬意を表したい)

やってて思ったのは、開発自体は楽しいんだけどモンスターの情報入力とかは地道で面倒で辛かった。あとゲームプレイしたい時間を削って開発するのも辛かった。

でも一番辛かったのは、宣伝するのが難しくて火がつかなかったこと。使ってくれた周りの人とかごく一部の僕のTwitterフォロワーの人達にはすごく評判良かったものの、当時ゲームの全盛期でハッシュタグ付けても文字通り秒で流れていくし、目にとまらない。個人レベルでの宣伝って難しいのを思い知らされた。

技術的にはPWAに触れれたし完全に静的にアップするんでもアイデア次第ではいろいろ活用できるなーって感触が得られたのは大きい。

YANTAN

新しいタブ用の拡張って前からしっくり来てなくて。と言うのも綺麗だけど自分がとった写真じゃなくてどっかの誰かがとったやつだったりとか。あとは単純なメモが欲しかった。ある日に、あれ、SPAの技術使えばChrome拡張って作れるんじゃね? とひらめいたから作った。

CSSでかけれるフィルタをフルに搭載して、カスタマイズ性の高いものが作れたのは良かったし、なによりこれも使ってくれた人からけっこう評判良く、自分でも常用している(そりゃあ自分が欲しくて作ったわけですし)

苦戦したのは、Markdownのリスト記法の入力保管とか。入力保管って自分で実装すると以外に泥くさいことしなきゃなんなくて。とはいえなかなか楽しかった。あとこれもマーケティング的に上手くいってない。やっぱり自分のTwitter、GitHub、ブログ以外のところで上手いこと宣伝活動していかないといけないんだなぁと思う。

cz-conventional-changelog-ja

いろいろ作ってたなかでCommitizenが凄く良くって、もっとGitのコミットメッセージをちゃんと書く文化が周りにも広まればいいなぁと思ってガっと訳した。

エゴサーチしてみると影響を受けてフォークして別の何かを作ってくれたりもしてくれてるようだし、嬉しいかぎり。また、翻訳フォークとはいえNPMライブラリデビューできたのは良かった。

自分は今はcz-customizeを使ってるので、使ってないけど今もすこーしダウンロードされてるようなので嬉しい。

その他

世に出したのはこれぐらいで、業務のわりと余裕がある時期にGASを使ってGitHubのプルリクとかをChatworkに通知されるWebHook作った。GASはスプシでデータ持てるし、タダでWebアプリ的なことができるから思ってるよりアイデア次第でいろいろ化けそう。このネタで外部でLTもしたっけ。

あとはRailsとVueでイベントのペライチのWebページを作れるWebアプリのプロトタイプも作ったっけ。これはいろんな技術の中で模索して、結局リリースレベルに持っていく前に頓挫してしまった。でもアイデアはアリだと思うのでいつかちゃんと形にしたい。

所感とこれから

こうしてみると仕事以外でそこそこ作ったなあ、と思う。実感としては「やってみた」「つくってみた」は凄い大事なんだけど、さらにちゃんと自分以外の人が使えるレベルまで自分なりに仕上げてリリースする、っていうのは本当に力になった気がする。ツライけど。

やってみたレベルだとローカルどまりでデプロイとか運用とかは考えなくていいので、そもそも設計も違ってきたりする。それに「人が使える」というレベルは自分が想像するよりけっこう遠い。自分はアイデアの発案だしUIもロジックも実装して、概念も把握してるから説明無しで使えるけど、いざ始めて人が使うとすると全然配慮が足りなかったりUIが悪かったりする。業務でやってると他の役割の人がカバーしてくれたりするけど独りプロダクトだと全部そういうとこまで見すえてやらなきゃいけない。

そういう苦労した経験が事実として今年後半になって仕事をするうえでもしっかり活きてきたなぁと実感している。

最近ブログコミュニティに入ってちゃんとブログをこうして書くようにしてるけど、作ってみたものはちゃんとリリースすると、文章のアウトプットにも匹敵するか、もしくはそれを遥かに凌駕するリターンがあるので本当にオススメです。ツライけど。

エンジニアになるときの他の会社の同期とか、今の会社の同僚とかを見てもブログとかにアウトプットしてる層もそもそも多くないけど、趣味でもリリースまでちゃんとやりきったアウトプットしてる人って本当にごく少数。それにはエンジニアリング力だけじゃなくてアイデアとか他の力も要求されるので簡単ではないんだけど、それにしても少数。

やっぱりユーザーが居たり使ってくれて「いいね!」ってくれる人がでてくると本当に嬉しいです。今も1つ作りかけてとりあえず実用できないこともないギリギリレベルまで来たので、来年もいろいろリリースまでちゃんとやるのを意識しつつ、さらにそこで得た知見を文章でもアウトプットしていきたい所存。