CIを最初に入れておくと開発体験が良くなる

最近たまに趣味でどうでもいいサイトを作っているんですが、いちいち手でデプロイするのとかがめんどくさいのでcircle ciを使ってみている。ドキュメントを適当に読み流すだけでも非常に簡単に使えるし、githunとの連携も簡単。↓のような設定ファイルをレポジトリに置いておくだけで、PRを出したらテストを流してくれて、テストが通ってマージをするとfirebase hostingにデプロイしてくれるので、ひたすらコードを書いていれば良い状況になる(完全な初心者なので、設定がおかしいところがあったら教えてください)。

version: 2

jobs:
  deploy:
    docker:
      - image: circleci/node:10

    steps:
      - checkout
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "package.json" }}
      - run:
          name: 'install dependencies'
          command: yarn
      - run:
          name: 'install firebase tools'
          command: yarn add -D firebase-tools
      - save_cache:
          paths:
            - node_modules
          key: v1-dependencies-{{ checksum "package.json" }}
      - run:
          name: 'build'
          command: yarn build
      - run:
          name: 'deploy'
          command: ./node_modules/firebase-tools/lib/bin/firebase.js deploy --only hosting --project "$FIREBASE_PROJECT" --token "$FIREBASE_TOKEN"

  test:
    docker:
      - image: circleci/node:10

    steps:
      - checkout
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "package.json" }}
      - run:
          name: 'install dependencies'
          command: yarn
      - save_cache:
          paths:
            - node_modules
          key: v1-dependencies-{{ checksum "package.json" }}
      - run:
          name: 'test'
          command: yarn test

workflows:
  version: 2
  ci:
    jobs:
      - test:
          filters:
            branches:
              ignore: master
      - deploy:
          filters:
            branches:
              only: master

CIがちゃんとしているとなんとなく嬉しくて、まじでどうでも良い趣味の開発しかしていないのに満足感が出てくる。自明なことだが、CIみたいなものは開発の初期に入れるほど通算の効用が大きくなるので、なんか作ろうと思ったら本格的な開発を始める前に設定をしておくべきだと気づいた。俺も起床したら自動的に会社にデプロイされるようにしたい。

生活におけるビールの改善

昔からけっこうビールが好きなのだが、就職してからは金麦糖質オフ500mlの6缶セットを日曜日に買って1週間を過ごすというビール界の公務員のような生活を送っていた。最近、人生を良くしていきたいという思いが出てきて、特に大した趣味もないので、日常的に良いビールを飲んでいくかという気分になってきた。非常に昔はIPAというジャンルのビールが好きだったな...というおぼろげな記憶と、家から徒歩5分くらいのところにある巨大スーパーのビール売り場に大量にIPAが売っているという幸運が合わさることにより、家に↓のようなビール群が登場した。どれもすごくうまくて、風呂上がりに飲んでいる。

インドの青鬼 350ml×24本

インドの青鬼 350ml×24本

Goでインタプリタ開発記(1)

今日から「Go言語でつくるインタプリタ」を読んでいる。

Go言語でつくるインタプリタ

Go言語でつくるインタプリタ

Go言語で、0から簡単なスクリプト言語を作っていこうという本です。簡単とは言っても、配列・ハッシュや高階関数も実装するらしいので結構夢がある感じがする。

読む目的は主に2つ。

インタプリタを作るということに関してだと、前にjavascriptで簡単な言語を実装するという記事も書いたし、「2週間でできる! スクリプト言語の作り方」という本も途中まで読んだ。しかし、いまいち理解が浅い気がするので、0から外部ツールを使わずにスクリプトを書く「Go言語でつくるインタプリタ」をやりきってスクリプト言語の実装の仕組みをちゃんと理解したい。

また、最近仕事でGoを書いたら結構面白くて、Goをまともに書けるようになりたいというのもある。仕事で書いたのはすごく小さいプログラムだが、インタプリタはシンプルなものでもそれなりに大きいコードベースになると思うので、Goでそれなりにでかいコードをどういう風に書けば良いのか学べるとありがたい。

今日は1章まで読んでLexerを実装した。インタプリタがプログラムを解釈するためには何段階かの工程を踏むのだが、Lexerはその中で一番最初のトークナイズを行うプログラムです。トークナイズは、プログラムという長い文字列を意味のある字句(トークン)に区切っていく作業。例えば、以下のようなプログラムがあるとすると、

if (a == 1) return 'hello'

Lexerはこの単なる文字列を、if, (, a, ==...のようなトークンに分ける作業を行う。文字列を意味の塊であるトークンに分けるというLexerの作業は当然だが大事で、例えば===, =という2つの連続した=なのか一つの演算子==なのかは、事前に決めたルールに基づいてLexerが決めるのである。

今回Goで書いたLexerはコード量で言うと300行くらいの小さなものだが、ちゃんとトークナイズできていてすごい。とりあえず今日で、以下のような入力プログラムをトークンに分けて表示するREPLができたので良かった。明日から構文木を作ったりしていくと思うので、引き続きがんばっていきたい。

>> let a = 1;
{Type:LET Literal:let}
{Type:IDENT Literal:a}
{Type:= Literal:=}
{Type:INT Literal:1}
{Type:; Literal:;}

>> let f = (a, b) { a + b; }
{Type:LET Literal:let}
{Type:IDENT Literal:f}
{Type:= Literal:=}
{Type:( Literal:(}
{Type:IDENT Literal:a}
{Type:, Literal:,}
{Type:IDENT Literal:b}
{Type:) Literal:)}
{Type:{ Literal:{}
{Type:IDENT Literal:a}
{Type:+ Literal:+}
{Type:IDENT Literal:b}
{Type:; Literal:;}
{Type:} Literal:}}

今日時点のコード:GitHub - ymr-39/monkey-lang at 433709c6872df6e4bf13bf58df2788fcdc747cad

ファイナルカレーを作った

インドカレーを作ることしか趣味がないのでよくインドカレーを作っているんですが、久しぶりに原点に帰ってファイナルカレーを作ってみた。

f:id:ymr-39:20181120000552j:plain

ファイナルカレーは、「いちばんおいしい家カレーをつくる」という本に載っている、日本のカレーとインドカレーの良いとこどりをしたカレーのことです。スパイスと市販のカレールーを両方使うので、スパイスの香りと日本のカレーのコクが両方楽しめてありがたい。

いちばんおいしい家カレーをつくる

いちばんおいしい家カレーをつくる

原点に帰って...というのは、自分が異常にカレーを作りだしたきっかけが↑の本だからです。今までまったく料理をしたことがない人生だったのだが、「いちばんおいしい家カレーをつくる」を読むと一瞬でおいしいカレーが作れる。

typescriptでreact/reduxアプリを書くときの方針

昨日から、typescriptでreact/reduxを書く練習をしている。今日は、typescriptを使ってreact/reduxアプリを作るときの方針(どこに何をどう書くか)を定めることを目標に、サンプルとしてtodoアプリを作ってみた。

まず、react云々の前に、typescriptの基礎を理解していないので、以下の記事を読んで勉強をした。まだ理解できていない気がするが、とりあえずtypescriptのプロみたいな人が書く謎の型の意味がわかるようになった。

次に、typescriptとredux+reactの組み合わせ方を勉強した。特にreduxのaction creator周りは普通に書くとtypescriptと組み合わせるのが難しいようで、いろんな工夫の仕方があることがわかった。

いくつかの記事の方法の良さそうなところを取り上げて、自分なりに納得できる方針でtodoアプリを書いてみた。

github.com

ディレクトリ構成は以下の通り。最近知ったDucks Patternというパターンに従ってmoduleに分けている(と言っても今回はファイルが1つしかないが)。

src
├── components
│   ├── App.tsx
│   ├── FilterSelect.tsx
│   ├── Form.tsx
│   └── TodoList.tsx
├── index.tsx
└── redux
    ├── modules
    │   └── todos.ts
    ├── store.ts
    └── types.ts

actionについて

人それぞれでもっともやり方が分かれそうなaction周りの定義。今回は、Union型を使って、moduleごとに全てのactionをまとめた型を作ることにした。javascriptで書くと、タイポを防いだりする目的でconst ADD_TODO = 'ADD_TODO'みたいな定義をすると思うが、typescriptだと文字列リテラルが型として働くので以下のように書ける。

export interface Action<T> {
  type: T;
}
export interface PayloadedAction<T, P> {
  type: T;
  payload: P;
}

// moduleごとに全てのactionをまとめた型を作る
export type TodosAction =
  | PayloadedAction<'ADD_TODO', {title: string}>
  | PayloadedAction<'TOGGLE_TODO', {id: string}>
  | PayloadedAction<'CHANGE_FILTER', {filter: Filter}>;

// ↑のおかげでaction creatorを書くときにいい感じに補完が効くようになっている
export const addTodo = (title: string): TodosAction => ({
  type: 'ADD_TODO',
  payload: { title },
});
export const toggleTodo = (id: string): TodosAction => ({
  type: 'TOGGLE_TODO',
  payload: { id },
});
export const changeFilter = (filter: Filter): TodosAction => ({
  type: 'CHANGE_FILTER',
  payload: { filter },
});

reducerについて

reducerは特に悩むところがなかった気がする。actionで型をつけたおかげで補完が気持ちよく効くことに感謝してたら書き終わった。

export const TodosReducer: Reducer<TodosState, TodosAction> = (
  state = todosInitialState, action: TodosAction,
): TodosState => {
  switch (action.type) {
  case 'ADD_TODO':
    return {
      ...state,
      todos: [
        ...state.todos,
        { id: uuid(), title: action.payload.title, completed: false },
      ],
    };
  case 'TOGGLE_TODO':
    return {
      ...state,
      todos: state.todos.map((todo) => (todo.id !== action.payload.id) ? todo : {
        ...todo,
        completed: !todo.completed,
      }),
    };
  case 'CHANGE_FILTER':
    return {
      ...state,
      filter: action.payload.filter,
    };
  default:
    return state;
  }
};

componentについて

bindActionCreatorを使うと、DispatchActionをうまく書くのが難しい。今回は、bindActionCreatorを使いつつちゃんと型が働くように、それぞれのcomponentで使うactionをまとめたobjectを作った。

// このcomponentで使う全てのactionをまとめたobjectを作る
const actions = { toggleTodo };

interface StateProps {
  visibleTodos: Todo[];
}
// DispatchPropsはactionsを使ってこのように定義しておくと良い
type DispatchProps = typeof actions;

const TodoListPresentation = (props: StateProps & DispatchProps) => (
  <div>
    <ul>
      {props.visibleTodos.map((todo) => (
        <li
          key={todo.id}
          style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}
          onClick={() => props.toggleTodo(todo.id)}
        >
          {todo.title}
        </li>
      ))}
    </ul>
  </div>
);

const mapStateToProps = (state: AppState): StateProps => {
  const { todos, filter } = state.todos;

  return {
    visibleTodos: filterTodos(todos, filter),
  };
};
const mapDispatchToProps = (dispatch: Dispatch): DispatchProps => {
  return {
    ...bindActionCreators(actions, dispatch),
  };
};

まとめ

typescriptでreact/reduxアプリを書く上で、とりあえず今の自分が納得できる方針を見つけられて良かった。これからtypescriptの理解が進むにつれて、書き方をアップデートしていきたい。今回決めた方針に沿ったboilerplateを作っておいた↓。書き方の方針が定まったので、次はアプリを量産して一発当てて引退することを目指したい。本当は何もせず気がついたら大金とともに引退していることが理想だが...。

github.com

android端末が欲しくなってきた

二年前くらいからiphoneを使ってて、会社からもiphoneを貸与されてるので完全にiphoneに飽きてきた。今年出たiphoneの価格が高すぎるということや、気が向いたときにandroid開発を勉強したいということもあり、android端末に興味が出てきた。良さそうな端末がないか調べてみて一番気に入ったやつ↓。

Essential Phoneという機種です。名前だけは聞いたことがあったけど、ちゃんと調べたのは初めて。

良いと思ったところ

  • 見た目がすごく良い
  • 価格がそこまで高くない
  • 性能がそこそこ良い
  • 余計なアプリが入ってこない

適当にネットでレビューを見てみたけど、悪くない感じがする(レビュー自体はバイアスがすごそうだが...)

typescriptでreact/reduxアプリケーションを書いてみた

最近よくjavascriptを書いているが、typescriptが使えると便利そうなので、勉強のためにreact/redux/react-reduxを使った単純なカウンターをtypescriptで書いてみた。

github.com

何もわからないところからのスタートだったので色々調べながらやったが、最終的にはほぼ以下の記事を参考にした。

qiita.com

感想

  • VSCodeを使ってるとjavascriptでもそれなりに補完が効くのだが、typescriptだと安定感が違いすぎる
  • typescriptは型推論してくれるが、まだいまいちどこは型を明示的に書く必要がありどこはないのかが理解できてない
  • そもそも型というものをあまり理解してない

とりあえず便利ということはわかったので、引き続き勉強してみる予定です。