マイペースなRailsおじさん

Ruby、Ruby on Rails、オブジェクト指向設計を主なテーマとして扱います。だんだん大きくなっていくRuby on Rails製プロダクトのメンテナンス性を損なわない方法を考えたり考えなかったりしている人のブログです。

Masonry Layoutを使いたい

masonry layout

pinterestみたいなレイアウトを、Masonry(石積み) Layoutと言うらしい。

pin.it

デモ

www.erikjo.com

こんな特性のものをmasonryと呼んでる気がします。

  • サイズの違う要素を並べられる
  • 表示領域のサイズが変わると並べ直す(これがおしゃれ)

二番目は副産物で、masonryのことではないかも?

使いたい

masonryが実装できて、SSR(next.js)対応で、速くて、コンポーネントライブラリを使いたい。

初めてコンポーネントを探した。 まずやりたいことがmasonryだってわかるまでが長かった。 わかってしまえば、githubで「masonry component」とおもむろに調べる。

github.com

でてきた。 Masonryにしたいところをで囲むだけでできる。 reactすごいさすが。

しかし初期表示とウィンドウサイズを変えたときの動きが結構もたつく。

hackernoon.com

この記事の筆者はIsotope · Filter & sort magical layoutsというJSライブラリで、どうして遅いか調べたそうだ。

だいたいこんなかんじ

  • フレキシブルにするための機能が重い
    • 様々なサイズの画像に対応している
    • サイズ変更の再描画に時間がかかる
    • 数百の要素のサイズを取得取得しなければいけない
    • 見えていないところの画像も再描画している

ので、

  • ページが大きくなるにつれて指数関数的に計算が増える。

のだそうです。

で、固定サイズの画像にだけ対応するなど機能を絞ってレイアウトエンジンを実装するくらいしか解決策がないと。

そもそも本当にMasonryにしないと行けないのかっていうのはちゃんと考えたほうが良さそうですね。

MX ERGO(トラックボール)買いました

買いました。
Logicool MXTB1s MX ERGO です。

f:id:ytnk531:20190224104121p:plain

裏は金属板と磁石でくっついていて、角度を20度駆られる。かっこいい。 f:id:ytnk531:20190224104203p:plain

感想

  • まだ慣れない。親指疲れる。
  • 机の上めっちゃ片付いた。それだけで結構嬉しい。
  • 開封時からところどころ汚れてた。だれのせい。
  • logicool optionの日本語が若干変。困らないけど。
  • 説明書なかったです。箱の中にも公式サポートにも。困らないけど。

SPAを作った

github.com

構成

  • API
    • Java
    • SpringBoot
    • Spring REST Data
  • UI
    • JavaScript(ECMAScript2015--2018)
    • react.js
    • next.js
    • materialUI
  • DB
    • mongodb

所感

  • API側はできるだけ楽ができそうなものを使った。
    • SpringBootはずっと使ってたので特に困らず。
    • Spring REST Dataはすごい。ほぼドメインオブジェクトを定義だけでRepositoryもAPIのエンドポイントもできる。すごい。 
    • mongoを使っていたおかげでテーブル
    • 割と複雑めな絞り込みとかもRepositoryに規約に従った名前のメソッドのシグネチャ書くだけでエンドポイントできちゃうのでほんとすごい。
    • 当たり前だけど、ドメインロジックが複雑になってきたらORMがないと苦しそう。
    • エンドポイントの名前がどんどん長くなってくのがカッコよくない。
  • フロントエンドの学習が目的だったので、よくわからないながらもSSRにしてみた。
    • コンポーネントはちゃんと設計しないとくっそつらい。設計できへん。
    • JSのPromise使いやすくていい感じ。
    • react.jsは最初は身構えたけど、そんなに覚えることはないし使いやすい。
    • materialUIはとってもよくできている。すばらしい。
    • next.js使うだけでほんとにSSRできた。すごい。
    • Array, Objectのメソッドとか調べながらやった。javaとは結構違うな。けっこう使いやすいと思う。map使えるし。

DDDの浅いまとめ

ドメイン駆動設計(DDD)が何なのかわかるまで時間がかかったので、あまり踏み込まずにまとめます。

DDDはわかりにくいか

little-hands.hatenablog.com

エリック・エヴァンスのDDD本が示しているのは、一つの大きなパターン・ランゲージである。パターン・ランゲージとは複数のソフトウェアパターンを組み合わせたもののことで、それを構成している各パターンには結び付きがある。

ドメイン駆動設計とは

ドメイン駆動設計(英: Domain-driven design, DDD)とはソフトウェアの設計手法であり、「複雑なドメインの設計は、モデルベースで行うべき」であり、また「大半のソフトウェアプロジェクトでは、システムを実装するための特定の技術ではなく、ドメインそのものとドメインのロジックに焦点を置くべき」であるとする[1]。この名称は、 Eric Evans が同名の著作で用いた[2]。

考え方

ソフトウェアを、そのソフトウェアが解決したい問題領域(ドメイン)とその他(永続化機構、ユーザインターフェースなどなど)に分けて考える。 ソフトウェアの価値や保守性の向上するためには、ドメインモデリングドメインを分析してソフトウェアのモデルにする)を頑張るといい。

とはいっても

ドメインモデリングに集中するための障壁はたくさんある。

戦略的モデリング(Strategic Modeling)

ざっくりいうと組織とかその編成の工夫。

戦術的モデリング(Technical Modeling)

設計について勉強し始めました

私は毎月イテレーションしながら開発しているプロジェクトに参加しています。 メンバーはSIerでSEとして経験を積んできた人が大半を占めています。 明確に設計を行う期間は設けておらず、設計書も作りません。 しかし、コードレビューを受けると、設計が悪い、外部設計を行っていない、基本設計ができていないといった指摘をもらいます。 私はWFでの開発経験が無いので、正直何を言っているかわかりません。 要は、専門用語の壁に阻まれコミュニケーションが取れていない状態です。

という問題を抱えていたので、設計について勉強し始めました。

まだ読んでいる途中ですが、外部設計と内部設計について気になったところをメモします。

外部設計と内部設計

  • 外部設計≒基本設計、機能設計、概要設計
    • 入力と出力を決める
    • ユーザーの振る舞い、外部システムとのメッセージング方法を決める
    • 顧客との合意を反映する
  • 内部設計≒詳細設計、プログラム設計
    • 入力から出力の実現方法を決定する

外部設計では、ユースケース分析、概念モデリングを行う。

  • ユースケース分析
    • システムが提供する機能とユーザーの振る舞いを明確にする
  • 概念モデリング
    • システムが扱うデータの構造を決定する

所感

私が今やっている仕事は実装だと思っていたのですが、実際は要件定義、設計、実装、移行まででした。 決めなければいけないことがバッサリすっぽ抜けいていたのです。 レビューのときにいろいろと指摘が入っていたのはまさに要件定義と外部設計を行っていなかったからでした。 アジャイルな現場においては、要件定義と設計についてもチーム内で議論を進めながらコードを書いていくことになります。私がうまく行っていなかったのは、「合意の上で決めないといけないこと」が何なのかわかっていなかったからでした。

アジャイルな現場にいながらウォーターフォールの設計手法を学ぶことは意味の無い事のように思えていましたが、私に撮ってはとても重要なことでした。 理由は、SIerのチームメンバーとコミュニケーションが円滑に進むようにになることです。これまで、〇〇設計はできているの?と聞かれても、なんのことかわからず、聞いても経験しないとわかんないよ的な答えが返ってくることが多かったのです。要は、決めるべきことは決まっているのか、何を決めるべきか把握しているのかということをチーム内で全く共有できていなかったのです。 設計について学ぶことで、チーム内で話し合うべきことがわかるようになったので、今後はもっとスムーズに仕事を勧めていけるように思います。

追記

途中で読み飛ばしたところもあるものの、全体を読み終えました。
設計について、広く浅く解説された本でした。
なぜ設計が必要なのかについてわかりやすく語られており、まさに「はじめての設計をやり抜く」ための本でした。
この本は設計について学ぶためのガイドとして非常に優秀な本であると思います。

日記 久々にプロコン系のプログラムをした

HackerRankでプログラミングをしました。 Dashboard | HackerRank

HackerRankの問題では、入出力系の部分はすでに実装されていて、問題になっている部分の関数やメソッドだけを実装すればいいようになっていました。 PaizaやCodeIQでは入出力系も書かなければいけなかった気がします。
Javaで書く場合、メソッドの引数と返値がたいていはプリミティブ型でした。
プリミティブ型を操作するのは久しかったのでちょっとてこずりつつ、プリミティブ型のストリームの使い方を覚えてみました。

調べたこと

  • IntStream
    • intのStream。Streamはクラスにしか使えないので、プリミティブ型専用のStreamが用意されている。他にLongStream、DoubleStreamがある。
    • mapとかforEachは普通のStreamと特に変わらず使える
    • collectやredumeは引数がちょっと違う。Collectorsがうまく使えない
    • boxedを使うとStreamに変換される
  • StringBuilder
    • char型の要素からStringを作るのに使える
    • (ちょっと使いにくいけど)Stringを反転させるメソッドがある

やったこと

HackerRankの問題を解いて撃沈した

www.hackerrank.com

これに挑戦しました。難易度Mediumがそんなに難しくなかったので、Hard余裕やろって感じでやりました。 計算量の減らし方がまったく思いつかず撃沈しました。

問題

  • 0埋めされた長さnの配列(インデックスは1から開始)が与えられる。
  • m個与えられるa, b, kの組み合わせを使って、配列のaからbに対してkを加算するという操作をm回行う。
  • 操作終了後の配列の中で最大の値を求める。

という問題でした。 細かい制約などは、是非HackerRankの問題ページをご覧ください。

nとmはわりと大きな数をとるので、計算オーダーが大きくなりすぎないように注意が必要です。

愚直なやり方(計算量やばい)

私が真っ先に思いついたやり方を示します。

gist.github.com

ものすごーく単純に、問題文通りの操作をします。 二重for文になっていることからもわかるように、a-b回(最大 n回)の配列操作をm回行うことになります (これはO(n**2)なのでしょうか…時間があれば調べます…)

HackerRankのテストケースを試すと、半分くらいのケースがタイムアウトして失敗してしまいました。 制約では、nとmは大きな数字をとりうるので当然の結果でした…

差分から計算できるようにする

HackerRankには、問題に対して議論できるDiscussionsページがあります。 こちらにとってもクレバーなやり方を示しているかたがいらっしゃいました。

Array Manipulation Discussions | Data Structures | HackerRank

Javaで実装すると以下のようになります。

gist.github.com

全体の流れは、

  • 長さnの配列を用意する
  • ちょっと工夫してqueryを適用する
    • 配列のa番目だけにkを足す
    • 配列のb番目からkを引く
  • 配列から最大値を計算する
    • 変数xに配列のi番目の値を加算する
    • 変数maxとxを比較して、大きければxを新たなmaxとする

といった感じです。

この方法は、用意した配列にクエリの適用結果を記録するのではなく、前の値とどれだけ差があるかを記録します。 そうすると、クエリを適用した配列のi番目の値は差分を記録した配列の先頭からi番目の値をすべて足した値になるというわけですね。

例えば、クエリを適用した結果が

[10,10,10,20,20,0,0]

となる場合、差分の配列を使えば

[10, 0, 0, 10, 0, -20, 0]

という形で表せるというわけです。 この方法なら、m個のクエリに対して必ず2回の操作を行えばいいわけですから、オーダーはO(n)で済むというわけですね。

あっぱれすぎました。世界は広い…。

日記

コードフィックス直前のラストスパートでした。 結構必死で思い出したけれど、あまり書くことがない。 いくら忙しくても自宅学習の時間はとりたいんじゃ~。

調べたこと

  • npm
    • package.jsonで実行するファイル名を指定できる
  • SRE(サイトリライアビリティエンジニア)という職業
    • いわゆるコードが書けるインフラエンジニアの進化系?
    • 大学時代はコンピュータネットワーク選考だったこともあってめっちゃ興味あります

やったこと

今週は家でコード書けませんでした…

考えたこと

テストを考えながらコードを書く。

TDDでは先にテストを書こうっていうのを推奨してますよね。 単体テストを書くようになって、コードを書く前、あるいはインターフェイスや基本的な部分ができた時点でテストを書いておくメリットがわかってきました。 私が感じるのは、テストを書くことを考えることで、設計がよくなるということです。 単体テストのために設計をゆがめてしまうのは良くない、みたいな意見を見ますが、私の今のところの浅い経験ではそういったことを感じたことはありません。 設計がよくなるというのは、 - 1つの機能の大きさがテストをしやすい大きさに収まる - メソッドやクラスを使う側のコードを書くことで、イケてないインターフェースに気付ける といったことを感じるということです。 最近は、テストから書くようにしているのですが、締め切りに追われているとやはり焦ってテストコードが後回しになってしまったりしますね。 テストを書くのに慣れていこうと思います。