旧gaaamiiのブログ

間違ったことを書いている時があります。コメントやTwitter、ブコメなどでご指摘ください

HTML要素を加工したReactコンポーネントに属性値を渡して展開して入れ込む方法

具体的にはlabelみたいなものですね。Labelというコンポーネントを作って、htmlのlabelと同じように属性値を渡しつつ、独自のスタイルを当てたりするコンポーネントをつくりたいみたいな。

こうする

const Label = (props: React.Props<{}> & React.HTMLLabelAttributes<HTMLLabelElement>) => {
  const { children, ...attributes } = props
  return <label {...attributes}>{children}</label>
}

「いつも「時間がない」あなたに:欠乏の行動経済学」を読んだ感想

Kindleストアを眺めていて、あっこれおれ読まないとダメなやつじゃん、と思って読んだ。面白かった。

借金の話

時間の話を、借金の話とかぶせて説明されたりして、納得感あった。

処理能力の制約

このへんの文が個人的には熱かった。

教育が良いことであるのはまちがいない 。しかし貧困者が犠牲を払わずに受けられるものであるかのように扱われているが 、実際には処理能力への高い代償がともなう 。本人が集中できずに教育の努力が無駄になるか 、本人は集中するが処理能力に負荷がかかるか 、いずれかである 。本人が実際に訓練やインセンティブに集中するとき 、何に集中しないことになるのだろう ?新たに課された授業はほんとうに 、彼が本を読んだり子どもと過ごしたりするためにひねり出した貴重な時間をつぶすだけの価値があるのだろうか ?

貧困者が貧困に陥る原因は、お金の教育がされていないからだ -> じゃあお金の教育プログラムを受けさせればいいはず。みたいなことがされてるけど、そこには処理能力という見えてない制約があるんじゃぞ、そこも考慮しないとだめよ、というような話。

感想

この本から得られた個人的な教訓としては、借金よくないね、時間あるときに前もってやるべきことやろうね、余裕はある程度持とうね、というごく当然のことなんだけど、それがいかに難しいことか、ということを本書を読んで改めて知ることができた。

自分もこの本に書かれているような失敗を何度もしているので、興味深く読めた。自分は幸い借金はないけど、時間の使い方についてはこの本の言い方でいうとジャグリング状態だ。スラックがない。

何度も読み返しながら、実生活を改善していきたい。

アフロ田中という人生漫画について

一気に読んでしまうほど面白くはないけど、読みながら一緒に歳をとれて、漫画の中のエピソードが自分の友だちとの思い出みたいな感覚で残っていくので面白い。いまは結婚アフロ田中の3巻が最新だけど、そこから読み始めてもいい。

ウェブフロントエンドのビルド設定を単純に考える

ウェブフロントエンドは設定周りがひたすらつらくて、なにかプロジェクトを作ろうとするとそれだけで挫折してしまうことが珍しくない。その辺を簡単にするツールもあるけれど、その中身が何をしているものかわからないと、設定の追加や最適化ができなかったりして結局つらいことになったりもする。無駄に難しいことに向き合うのは誰だって嫌なので、ウェブフロントエンドのビルド周りの設定って何が必要なんだ...?というのを、なるべく難しい話を省いて書いておこうと思った。

何もなくてもいい

まず、簡単なウェブサイトにちょっとしたスクリプトを入れるのであれば何もなくてもいい。テキストエディタでindex.htmlとindex.jsを作って、index.htmlに<script src="index.js" />を書けばいい。ほんとにちょっとしたものであれば、index.htmlに<script>alert('hello world');</script>と書けばいいだけかもしれない。

モジュール

簡単なスクリプトでも、1000行近いindex.jsになってしまっていたら、そのプログラムは読むのが大変。なので、他のプログラミング言語と同様に、複数のファイルに分けて、わかりやすくしたい。index.htmlは以下のようになる。

<script src="a.js">
<script src="b.js">

b.jsで、a.jsの機能を使うという依存関係があるため、a.jsはb.jsより先に読み込まれている必要があり、そのため<script src="a.js">の記述が先に来る必要がある。

これでも困らなければこれで良い。しかしファイルが多くなってくると、管理はどんどん大変になってくる。 そこで、モジュールとして扱えるようにしたくなる。

b.jsで、このように記述して、a.jsからモジュールをimportできるようにする。

import A from 'a';

A.hello();

モジュールバンドラーの導入

上のような感じで、モジュール分けられた〜良かった〜。となるものの、ファイル数が多いと、サーバーからJSファイルをダウンロードするのをモジュールの数だけやることになる。HTTP 1.1だとこれがけっこうな時間になりかねない。

f:id:shgam:20190324230744p:plain

そこで、ファイルを束ねて返すために利用できるのがwebpackなどのモジュールバンドラー。 設定を書いて、コマンドを叩くと、複数のモジュールが一つのファイルに束ねられる。なので、それをサーバーから配信するときも1つのファイルを返すだけになって助かる。

モジュール束ねるだけじゃなくてもっといろいろやりたい

ウェブアプリ開発では、モジュールを束ねる以外にもいろいろやりたいことが出てくる。webpackでは、loaderという、バンドル対象のソースコードを変換していくための設定が書ける。

ES5にしたい

上で書いたimportなどは、そのままだと古いブラウザ(Internet Explorer 11とか)だと動かない。じゃあどうするのっていうことで、古いブラウザで動くJavaScriptにしたくて、それがES5(ECMAScript 5)という仕様。babelというツールがあり、これを使うとES5にできる。だから古いブラウザでも動く。古いブラウザを使っているお客さんにもアプリケーションを使ってもらえる。

JavaScriptではなくてTypeScriptで書きたい

JavaScriptは動的型付けの言語なので、静的型付けの言語でウェブアプリを書きたいとなると、だいたいTypeScriptを使うことになる。これも、設定を書けばできる。

SASS使いたい

これも設定を書けばできる。

Lintかけたい

これも同上。


...と、ほかもいろいろ羅列しようとすると疲れそうなのでもうやめる。

上に書いてきたものは情報としてあまり価値がないかもしれない。 時間が進んで、古いブラウザを切れるようになってくると前提が変わってくる。すると、必要な設定も変わってくる。コードも変わってくる。 だから、ウェブアプリ書いてる人間はいつまで設定と格闘しなきゃいけないんだつらいっていう気持ちにもなるけど、前提が変わる以上はずっとやらないといけないことだとは思う。

単純に考えると、どういう環境で動くものを作りたいか、どうコードを書きたいかという2点を考えて今後もやっていけばよさそう。

SPA時代について

SPAについてのブログ記事を読んだ。自分が考えていることを箇条書きにしておく。

  • ビューもRailsにのっかって書いたほうが、生産性とか安心感が得られるかもしれない。
  • それを捨ててまでSPAにしたからといって使いやすいアプリケーションになるとは限らない。
  • すごい頑張ってSPAにして、すごい気を使って作って、ほんのちょっと使い勝手が良くなるかもしれない。
  • ほんのちょっとの使い勝手の良さが競争に勝つためにすごい大事かもしれないし、そうではないかもしれない。
  • 既存のアプリケーションをSPAにしようとして、スケジュールが遅延して苦しいことになるかもしれない。

そんな末端を最適化しなくとも、ちゃんと使えるシステムを作っていれば十分なのかもしれないし、逆にそうやって言ってる間にみんな末端を最適化したサービスだらけになっていて競争で勝てなくなるかもしれない。仕事難しい。

基礎からわかるElmを読んだ感想

1年半くらい前に注文したものの、Elmのバージョンが0.18->0.19に上がる都合とかで出版予定日が延びていたElm本がついに昨日、自宅に届いていた。感動した。

勉強になったところとか、感想を書いていく。

基礎からわかる Elm

基礎からわかる Elm

Amazon

型の話

Elmといえば静的型付け言語であり、No Runtime Errorなウェブアプリを書けるという良さがある。 一方で、型が読めないと何が何だかわからない。型の話がわからないと、自分で型を書けないのはもちろん、なんといってもドキュメントが読めなくて困る。

この本では、50〜71ページのおよそ20ページでこのElmの型についての説明が書かれている。この辺の節を読むと、制約つきの型変数、type aliasがコンストラクタを生成すること、カスタム型とパターンマッチなどについて学べる。とても丁寧でわかりやすい。特にtype aliasとかカスタム型は自分で勉強したときよくわからなくてつらかった思い出があるので、もっと早くこの本が欲しかった。

MaybeとかResultとか

Elmにはnullとかnilってものはないという話で、その代わりMaybeって型がある。Maybeはモジュールにもなっていて、withDefaultとかmapとかandThenなどの関数が生えているのでだいたいやりたいことはできる。なんとなく自分の理解が怪しかったので復習がてら読んだ。

Resultも似たようなものだけど、Maybe以上に自分の理解が怪しかったのはおそらく、APIへリクエスト投げてレスポンス取得して云々みたいな処理を実装しようというときに初めてこのResultに出会ったからだと思う。ElmでHTTPリクエストを送る処理はHttpというモジュールでやる。そこでResultという型が出てくるのだけど、もちろんResult自体はそれ以外のところでも使えるし、Httpのためだけのものでもない。

本書では、

Resultは失敗するかもしれない結果を表すデータ構造です。

と簡潔に書かれていて、例示されているコードもHttpとかは関係のないものになっている。「ElmでAPIへリクエスト投げてデータ取得する実装をやろう」となって、「実装してみたもののResultってやつがなんだかよくわからない」となったときに本書のこの辺を読むとすっきりわかってよさそう。

描画の仕組みと高速化

Html.KeyedとHtml.lazyの話。

ReactでもkeyアトリビュートとReact.PureComponentがあり、これらと同じようなものだと思う。

ナビゲーション

onUrlRequestonUrlChangeの説明がありがたい。 ナビゲーション周りの知識はSPAつくるときに必須なので、これが簡潔にまとめられているのは助かる。

感想

Elmを使って、実行時エラーが発生しないアプリを作れるのは魅力的だけど、新たに言語覚えるのはしんどい。 日本語の書籍にまとまったことで、言語覚えるしんどさが軽減されて、Elm人気もじわじわ高まっていくんじゃないかと思った。

combineReducersってなんだ

最近、Structuring Reducersとかそこらへんのページを読んでる。

なんで読んでるのかというと、Reduxでウェブアプリケーション書いていて、reducerどう分けるのがきれいなんだっていうのがいまいちわかっていない気がしたから。Immutable.js入れときゃいいのか?とか考える前に、ここを読むべきっぽいので読もうみたいな気持ち。

その中で、combineReducersっていう関数が何をしているのか気になったので、調べた。

combineReducersは複数のreducerたちを、createStoreに渡せる一つの関数の形にしてくれるやつらしい。 実際何をしているのか見てみる。

てきとうにreduxをnode_modulesにインストールしてあるプロジェクトで、nodeのREPLを立ち上げる。

$ node
>

そんで、redux.combineReducersという関数を雑に確認

> const redux = require('redux')
undefined
> redux.combineReducers
[Function: combineReducers]
> redux.combineReducers.toString()
'function combineReducers(reducers) {\n  var reducerKeys = Object.keys(reducers);\n  var finalReducers = {};\n  for (var i = 0; i < reducerKeys.length; i++) {\n    var key = reducerKeys[i];\n\n    if (process.env.NODE_ENV !== \'production\') {\n      if (typeof reducers[key] === \'undefined\') {\n        warning(\'No reducer provided for key "\' + key + \'"\');\n      }\n    }\n\n    if (typeof reducers[key] === \'function\') {\n      finalReducers[key] = reducers[key];\n    }\n  }\n  var finalReducerKeys = Object.keys(finalReducers);\n\n  var unexpectedKeyCache = void 0;\n  if (process.env.NODE_ENV !== \'production\') {\n    unexpectedKeyCache = {};\n  }\n\n  var shapeAssertionError = void 0;\n  try {\n    assertReducerShape(finalReducers);\n  } catch (e) {\n    shapeAssertionError = e;\n  }\n\n  return function combination() {\n    var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n    var action = arguments[1];\n\n    if (shapeAssertionError) {\n      throw shapeAssertionError;\n    }\n\n    if (process.env.NODE_ENV !== \'production\') {\n      var warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache);\n      if (warningMessage) {\n        warning(warningMessage);\n      }\n    }\n\n    var hasChanged = false;\n    var nextState = {};\n    for (var _i = 0; _i < finalReducerKeys.length; _i++) {\n      var _key = finalReducerKeys[_i];\n      var reducer = finalReducers[_key];\n      var previousStateForKey = state[_key];\n      var nextStateForKey = reducer(previousStateForKey, action);\n      if (typeof nextStateForKey === \'undefined\') {\n        var errorMessage = getUndefinedStateErrorMessage(_key, action);\n        throw new Error(errorMessage);\n      }\n      nextState[_key] = nextStateForKey;\n      hasChanged = hasChanged || nextStateForKey !== previousStateForKey;\n    }\n    return hasChanged ? nextState : state;\n  };\n}'

てきとうなreducerを渡して何がかえってくるかを見てみる

> redux.combineReducers({ hoge: (state, action) => { return state }})
[Function: combination]

関数が返ってきたので、これのなかみを雑に見る。

> redux.combineReducers({ hoge: (state, action) => { return state }}).toString()
'function combination() {\n    var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n    var action = arguments[1];\n\n    if (shapeAssertionError) {\n      throw shapeAssertionError;\n    }\n\n    if (process.env.NODE_ENV !== \'production\') {\n      var warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache);\n      if (warningMessage) {\n        warning(warningMessage);\n      }\n    }\n\n    var hasChanged = false;\n    var nextState = {};\n    for (var _i = 0; _i < finalReducerKeys.length; _i++) {\n      var _key = finalReducerKeys[_i];\n      var reducer = finalReducers[_key];\n      var previousStateForKey = state[_key];\n      var nextStateForKey = reducer(previousStateForKey, action);\n      if (typeof nextStateForKey === \'undefined\') {\n        var errorMessage = getUndefinedStateErrorMessage(_key, action);\n        throw new Error(errorMessage);\n      }\n      nextState[_key] = nextStateForKey;\n      hasChanged = hasChanged || nextStateForKey !== previousStateForKey;\n    }\n    return hasChanged ? nextState : state;\n  }'

中身を見ると、なるほどたしかにstateのキーごとにreducer(state, action)を呼び出して、次の状態を作っている。

function combination()というのを見て、なんだ(state,action) => stateの形になってないじゃないかと一瞬思ったけど、よく見るとarguments[0]をstateに、arguments[1]をactionに代入しているので、combination()combination(state, action) と呼び出せることがわかる。関数定義で引数がなさそうでも、引数を渡して呼べて、それをargumentsでアクセスできるらしい1

呼び出してみる。

> const combination = redux.combineReducers({ hoge: (state, action) => { return state }})
undefined
> combination(1, {})
Error: Reducer "hoge" returned undefined during initialization. If the state passed to the reducer is undefined, you must explicitly return the initial state. The initial state may not be undefined. If you don't want to set a value for this reducer, you can use null instead of undefined.

エラーになった。さすがに雑すぎたようだ。このエラー文で言われている通り、初期状態をundefinedにしたらいけないので、そこらへんもちゃんとしたreducerを渡して再度試す。

> const myCombination = redux.combineReducers({ hoge: (state = 0, action) => { return state }})
undefined
> myCombination({ hoge: 1}, {type: 'HOGE_ACTION', payload: 'hogehoge'})
{ hoge: 1 }
>

できた。雰囲気としてactionぽいものを渡しているけど、reducerで利用していないので、空のオブジェクトでも呼び出せる。

> myCombination({ hoge: 1}, {})
{ hoge: 1 }

以上で、combineReducersがほんとにただ複数のreducerをまとめるだけの普通のヘルパー関数であることがわかった。よかった。

Pageコンポーネントの共通処理をHOCにする

Reactでは継承よりも、HOCを使うのが推奨されている。HOCとはHigher Order Componentの略で、コンポーネントを引数にとってコンポーネントを返す関数のこと。

なので、たとえば似たような前処理をするページコンポーネントが複数あったとして、その共通処理を書く場合、

export default class UsersDetailPage extends UsersPage { ... }

みたいなことはせず

export default enhanceUsersPage(UsersDetailPage)

みたいな感じになる。

なんで継承じゃなくて関数...?という疑問は当然出てくるけど、以下に

Note that a HOC doesn’t modify the input component, nor does it use inheritance to copy its behavior. Rather, a HOC composes the original component by wrapping it in a container component. A HOC is a pure function with zero side-effects.

reactjs.org

と書かれて強調されているように、HOCはもとのコンポーネントの振る舞いは一切変えない。

HOCにコンポーネントを渡せば振る舞いが追加されたコンポーネントとして使えるし、HOCに渡さずそのままコンポーネントを使うこともできる。

React Routerを使って、イベントが起きたときにURLを変えつつ何か処理をする

SPAを作っていると、何かイベントが起きたときにURL変えつつなにか処理をしたいということがあります。 たとえば絞り込み検索で、クエリストリングだけ書き換えて画面更新したいというケース。具体的には/blog_posts から /blog_posts?tag=1 へ遷移するような感じです。history.listenにコールバックを渡すと、これが実現できたのでメモしておきます。

まずは実装例

interface Props extends RouteComponentProps {
  hoge: string;
}

class MyPage extends React.Component<Props, State> {
  constructor(props: Props) {
    super(props)
  }

  componentDidMount() {
    this.unregisterHistoryCallback = this.props.history.listen((location: LocationDescriptor) => {
      this.updateMyPageData(location.search.toString())
    })
  }
  
  componentWillUnmount {
    this.unregisterHistoryCallback()
  }
  
  private updateMyPageData(query: string) {
    // ...
  }

  private pushHistory(obj: any) {
    const query = QueryHelper.toQueryString(obj)
    this.props.history.push({ search: query })
  }
}

やっていること

URLつくる -> URLに紐付いた状態更新メソッド的なもの(updateMyPageData)を呼び出している。

やっていること詳しく

ポイントは、URLが変わったときに呼ぶコールバックの登録と解除。それを history.listen というメソッドで行っている。listenは、コールバックを登録してそれを解除する関数を返すので、登録時の返り値を保持しておいて、コンポーネントのunmountのタイミングでそれを呼べば良い。

追記

上記のやり方では props.match.params (たとえばURLが /users/{userId}/posts?hoge=fugauserIdの部分)を、最新のものを参照できなくて悩んでたのですが、以下の記事を読んで、React Routerのlocationを使えばいいことを知りました。

qiita.com

参考

overflow: visible scroll がうまいこといかなくてつらい

https://codepen.io/gaaamii/pen/VgrwMvcodepen.io

overflow: visible scroll;

と書いたらx方向ははみ出て見えて、y方向はスクロールになってほしいのだけどそうはいかなくてつらいという話。なんでx方向もscrollになるんだ。

コンビニ人間を読んだ感想

短くてパッと読めて面白かった。主人公が随分変わった人だったけど、共感できるところもあった。生きるの難しいけど、なにか一つでも没頭できる行為なりなんなりがあるのはいいことですな、という気持ちになった。

styled-componentsの良さがよくわからない

と、煽ってるような記事タイトルだけど、 煽りたいわけではなく、単にわからないというつぶやきです。

自分はいまCSS Modulesでやっていて、特に困ることがない。

最近styled-componentsのほうがよく聞くのはなんでだろう。 あっちのほうがなにかいけてるポイントがあるんだろうか。

2018年の振り返り

今年も色々あった。時間過ぎるのがあっという間で、気付いたら10年くらい経ってしまいそうなのでこうして思い出(?)をブログに残しておく。

1月

Reactを書いてた。Angularで書いたものをReact化するという少し変わった仕事だった。他にやるべきことはないか、なぜこれをするのか、という考えが足りなかった気がする。これをやりましょうというのを提案するべきだった。

2月

引き続きReactを書いていた。 組織的には、人がどんどん辞めていった時期。

3月

3月も人が辞めていた気がする。1〜3月の辞め具合がすごかったのでもはや何月に誰が辞めたか正確に覚えていない。

ここで、自分がそれまで携わっていたプロジェクトは開発を止めて、自分は異動する話になった。運良くやりたいことができるところへ異動になり、クビも切られなくてよかった。さすがにクビ切るというのは極端だけど、一瞬その会社での仕事がなくなったのは事実で、いろいろ考えた時期だった。

4月

新部署での仕事が始まる。ちゃんとしたRailsアプリケーションの開発を仕事でやるのは入社したばかりの頃以来で、ひたすら力不足を感じていた。あと会社が資金調達した。

5月

相変わらずひいひい言って大変だった。

6月

わりと大事な機能を開発することになり、これも大変だった。リーダーのレビューが最強で最高で学びが多かった。 難しかったのはオブジェクトの責務分けとか、RESTとして正しいURI設計をするだとか、たくさんテーブルを繋げて条件を指定するようなSQLの書き方だとか。あとRSpecもなかなかうまいこと書けなくて最初は特につらかった。

サーバーサイドの開発をするとき、esaでシーケンス図(UML)を書けて、それが考えを整理したり共有する上でとても役に立った。

7月

shgam.hatenadiary.jp

shgam.hatenadiary.jp

悩んでいる感じがこのブログにも残されている。今思うと、余裕がなかったとはいえwebpackerの設定直さないまま開発を続けていたのはとても良くなかった。

開発していた機能のリリースなどをした。

8月

React, Reduxなプロジェクトの雛形を用意してつく始めたり、Elmのあれをあれしたりしていた。

9月

仕事は引き続き、ReactとReduxのあれをあれしていた。

buildersconへ行ったり、ISUCONに出たりした。

shgam.hatenadiary.jp

shgam.hatenadiary.jp

10月

同じくReactの云々。

11月

Elmで途中まで作っていたものをデモでお披露目するということで、そちらを急いで進めたりなどした。その後のリリースまで持ってくのもけっこう大変で、Elm力が高まった気がする。スケジュール的には押してしまって反省あるのみ。

あと、RubyWorld Conferenceへ行った。

shgam.hatenadiary.jp

あと、結婚したり、歳をとったりもした。

12月

Elmで書いてたやつがリリースされ、Elmのアドベントカレンダーにも記事を投稿したりした。

qiita.com

その後は引き続きReactを書いてた。

会社が御茶ノ水へ移転した。それまでと比べて、戸惑うくらい快適なオフィスになった。 代々木もそれなりに長くいたので感慨深かった。またいつかいそじ行きたい。

shgam.hatenadiary.jp

一年通して

仕事全般について

1〜3月は会社が良い雰囲気ではなかった。業界的に人が辞めるのはよくあることかもしれないけど、それにしてもこんなに一気に…という感じだった(年の後半では人が増えてオフィスも移転して、雰囲気も明るくなって本当に良かった)。 当時は、困った、さあこれからどうするって感じで、そこで自分が関わってきたところも、問題を洗い出したりして、開発を止めることになり、そこを離れるということになった。

その時は、ああこうやって仕事って無くなるんだなと、はっきりとした危機感を持った。 事業的にいろいろ整理が発生するのは絶対あることだろうけど、突然仕事が無くなったときに、どこにも行き場がないみたいな状態にならないように精進していかなくてはと思った。今回に関しては運が良く、希望のところへ異動させてもらえた。

ウェブフロントエンドについて

自分の仕事に危機感を持ったこともあり、ウェブフロントエンドに関して考えることが多かった。 そこで考えて出てきたのは、やっぱりウェブアプリケーション使うなら、使いやすく、速く感じられるのが良いだろうということ。そのために必要な技術がウェブフロントエンドの諸々だと思っている。

iOSAndroidのネイティブアプリだったら、はじめからサーバー側のロジックととクライアント側のロジックは切り離されてるけど、古くから(クライアントMVCとかSPAが持て囃される以前)のウェブアプリケーションだと、サーバー側のコードの一部として管理されていて、密結合だったりする。すると、クライアント側での最適化みたいなのは難しく、基本的にユーザーは毎回サーバーから手元のブラウザへ、HTMLドキュメント全体をダウンロードして、画面を更新することになる。

Fluxみたいなパターンと仮想DOMみたいな仕組みで、ユーザーの行動に応じて画面のなかの必要な分だけ更新するようなアプリケーションが可能になった。ただウェブにはURLがあるので、フロントエンド側にルーターを持ち、ウェブのURLの表現を保つ工夫も必要になる。

もちろんSPAみたいなのは良いことばかりではなく、サーバーがリクエストに応じたHTMLドキュメントを返すだけというシンプルさを捨てることになる。実装の複雑度は増すし、ユーザーからの目線で考えてみても、SPAのほうが体験が良いと言えるのはちゃんと作られている場合だけで、不具合があったり不自然な画面遷移をしたりするものを作ってしまうと、SPAなんかしなけりゃよかったということになりかねないとは思う。それでも、自分はサーバーとクライアントは分けたほうが良いと思っている。APIと画面を分けるのは、サーバーはサーバーを、クライアントはクライアントのことをうまくやるのに集中できる環境をつくることだと思う。

しかし、モバイルで最高の体験を、と考えるならやっぱりウェブよりネイティブアプリだと思っていて、じゃあ上で書いたようなものは何をつくるために必要なのかと考えると、PCで使うSaaSみたいなものがあってると思う。「クラウドなんちゃらシステム」みたいなもの。そして、人がパソコンのキーボードを叩くのは多くが仕事かそれに近いようなときで、それ以外はみんなスマホを使ってる(と思う。すごい雑認識だけど)。だから、ウェブフロントエンドをさらに個人的な視点で狭く言うと、仕事でPCで使うときに使うシステムを使いやすくする技術になる。

今まさにやっている仕事もそれに近いものなので、これをどこまでの出来にできるかというのが、事業にも、自分のキャリアにも重要になっていると思ってる。なかなかうまくいかないこともあるけど、引き続き頑張っていきたい。

プログラミング言語について

Ruby(Rails)は、よく考えてる人が書いたものは洗練されていて、責務がしっかり分けられていてきれいという感想を持った。オブジェクト指向の本読みきらねばという気持ちが強まった。

あと、一時期Elmを書いたことにより以下のような気持ちが芽生えた。

  • 静的型付け言語良い
  • Lintとかなるべく自分で設定する必要がなく、コードのフォーマットとかは自動でされたほうが嬉しい

関数型言語についての感想は、関数の入力の型がその入力を制限していて、同じ入力に対して常に同じ出力になるっていう単純さが良くて、ほかの難しそうなことについては正直よくわかっていない。

特にオブジェクト指向デザインパターンのような、プログラム全体の整理整頓みたいなのをどうやるべきかというのがまだよくわかってないけど、Elmの場合は中心となる型があり、それをいじくる関数が一緒にまとまったものがモジュールになるという考え方っぽかった。

来年はGo言語も少し触ってみたいという気持ちになってる。

健康

大きい病気はしなかったけど、地味に疲れやすい体になってきてるなという気はした。 健康はなんかぼーっとしてるとどんどん奪われていくので、きっと健康オタクくらいの感じがちょうどいい。

生活

今年は結婚をしたので、人生設計を堅くしてこれからのことに備えていきたい。

人間関係

ありがたいことに、仕事でも親族関係でも友人関係でも、嫌いな人と接することがほぼない。とても恵まれていた。

インターネット上での活動

Podcastとかほとんどとれなかった。

きまべんという思いつきで始めたScrapboxプロジェクトが、熱意のある方々によって続けられていて、自分もやっていかなくてはと刺激される。

まとめ

今年もお世話になりました。来年もよろしくお願いします。