ytnk531の日記

日々調べたことを書きます。

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

私は毎月イテレーションしながら開発しているプロジェクトに参加しています。 メンバーは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つの機能の大きさがテストをしやすい大きさに収まる - メソッドやクラスを使う側のコードを書くことで、イケてないインターフェースに気付ける といったことを感じるということです。 最近は、テストから書くようにしているのですが、締め切りに追われているとやはり焦ってテストコードが後回しになってしまったりしますね。 テストを書くのに慣れていこうと思います。

日記

会社の書類に追われていました。

 

調べたこと

- redux

  - store、reducer、providerあたりの復習

- atomicデザイン

  - UIパーツを階層にわけて作る

  - 規模が大きいと、こういうのめちゃくちゃ効いてきますよね

- SSR サーバーサイドレンダリング

  - SPAのJSのダウンロードと初期表示画面の生成には時間がかかるので、JSをサーバーで実行してページ生成してしまおうという話

   - 理屈はわかりやすいんだけれども、やり方調べ中。

     - ユーザ固有の情報はどうやってくっつけるんだろうか。あとからクライアント側で実行?

      - SSR用のnodeのサーバーを用意する。

      - ルーターつかってページを分割していることとか考慮しないと行けなそう

 

やったこと

- webアプリを作り始めた

  - UIはmaterial-uiのreactコンポーネントライブラリを最大限使って構成

  - create-react-appで始めて、reduxを入れた

  - UIの状態をreduxをつかって分離した

 

考えたこと

- SSR、簡単そうに見えて難しくないか

- Most Valuable Productを作るには鍛錬がいる

  - こんなサービスあったら良さそう!と考えても、Valuableな部分は何かって考えていくと大したものが残らないことがよくある

  - なんか本さがしてみよう

日記 土日は休みたくなってきた。

調べたこと

  • MATERIAL-UI
  • 9 things every React.js beginner should know
    • React.js初心者が知るべき9つのこと
    • ちゃんと読んでないけど、大事なことが凝縮されていそうな気がするのでダラダラ読んでいく
    • Viewライブラリである
    • Model、Controllerの機能は持たない
    • コンポーネントを小さく保ちなさい
    • 「小さい」の規模感は状況によってことなるが、できる限り本当に小さくするのがよい。
    • Functionalなコンポーネントを書きなさい
    • アローファンクションを使ってrenderメソッドを書いてやると見やすいので、コンポーネントはclassではなくfunctionで表すようにしよう
    • ステートレスなコンポーネントを作りなさい
    • Redux.jsを使いなさい
    • prop Typesは必ず書きなさい
    • shallow renderingを使いなさい
    • JSX, ES6, Babel, Webpack, NPMを使いなさい
    • React, Reducのデベロッパーツールを使いなさい

やったこと

  • React.js環境構築
    • nvm
  • Materila-uiちょっとつかう

考えたこと

  • 特に面白いことは思いつかなかった。

@Mockでモックを初期化する方法は3つある。

mockitoでは、モックにしたい変数に@Mockアノテーションを付けるだけでモックを作れます。この場合、アノテーションを有効にする記述をする必要があります。アノテーションの有効化は、initMocksを呼び出す、Runnerを使う、Ruleを使うの3つの方法で行えます。

mockito

mockitoはモック作成、呼び出しの検証、スタブの作成が行えるユニットテスト用のJavaライブラリです。
以下は公式サイトにあるキャッチコピー。

Tasty mocking framework for unit tests in Java
Javaユニットテストのための味わい深い(?)モックフレームワーク

インストール

gradleを使っている場合は、build.gradleのdependenciesにmockitoを追加してください。

group 'net.example'
version '1.0-SNAPSHOT'

apply plugin: 'java'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.12'
    testCompile group: 'org.mockito', name: 'mockito-core', version: '2.21.0'
}

基本的な使い方

モックにしたクラスのメソッドにスタブを作ってテストするという使い方をよくします。

基本的なモック

mockの作り方

mockを作る方法は、mockメソッドを使う方法と、@Mockアノテーションを使う方法があります。

上の例で使っていたので、mockメソッドを使う方法です。

private List mockedList = mock(List.class);

もう一つが@Mockアノテーションを使う方法です。

@Mock
private List mockedList;

アノテーションを使ったほうが記述が少なく、見栄えもいいのですが注意が必要です。 @Mockに限らず、mockitoが提供しているいくつかのアノテーションを使うときはアノテーションを使ったMockを初期化する処理を書かなければいけません。

アノテーションを使ったmockを初期化する方法

@Mockとかを初期化する方法は3つあります。 私はRunnerを使うのが楽なので好きです。

initMocks()を使う

@Beforeなメソッドの中でinitMocksを使います。

initMocks

Runnerを使う

@RunWith(MockitoJUnitRunner.class)をクラスにつけます。 Mockito用のRunnerが適用されるので、Mockの初期化だけでなくスタブの用法が間違ってないか検証するなどの機能もあります。

Runnerを使う

Ruleを使う

JUnitのRuleを使ってMockitoJUnit用のルールを適用します。

@Rule public MockitoRule rule = MockitoJUnit.rule();

効果としてはRunWithを使った場合と変わらないようです。

Rule

情報源

Mockito (Mockito 2.21.0 API)

https://static.javadoc.io/org.mockito/mockito-core/2.21.0/org/mockito/MockitoAnnotations.html#initMocks-java.lang.Object-

MockitoJUnitRunner (Mockito 2.21.0 API)

https://static.javadoc.io/org.mockito/mockito-core/2.21.0/org/mockito/junit/MockitoRule.html

飲み会あったので日記つけるのつらかった

調べたこと

  • gitのコンフリクト
    • checkout --theirs [ファイル名]とcheckout --oursを駆使する

やったこと

考えたこと

Windows 10 Enterprise Editionは開発機として使えるか

エンジニアはMac、その常識をWSLが覆そうとしている。というような話を聞いてから久しい。 Windows10 homeを使ってみて、やはりそんなことはなかったなぁと思っていた。
そんな私のもとに、職場都合でWindows10 enterprise editionがやってきた。以下、1日触った感想。

Windows10 EE のよいところ

  • フォントレンダリングがきれい
    • Win7に比べて、だけれど。やっぱりMacにはかてない。ヒラギノがつよいのか。なんなのか。 - Windows Subsystem for Linuxが最高すぎる
    • ターミナルエミュレータがヤバいのを除けば最高。だってLinuxがそのまま使えるんですもの。
  • docker for Windowsがいいかんじ
    • 仕組みはまだよくわかっていないけれど、Docker Tool Boxみたいに後ろで動いている VMを気にしなくていい。
    • WSLからもdocker.exeで使える

Windows10の残念なところ

  • インストールめんどくさいい。
    • 後からわかったけど、Chocolatyというパッケージマネージャを使えばよかった。
  • ターミナルエミュレータが残念
    • cmd.exeがちょっとだけよくなったくらいのやつ。
    • i18n対応バグなのか、フォントの設定をしてもMSゴシックに戻ってしまう。
    • VcXsrvを使うとX Window Systemが使えるので、GNOMEとかのいい感じのターミナルが使えるんだけどまだ未設定。

設計ムズスギィ

先輩エンジニアに指摘して頂いて、自分のやっている設計がまだまだオブジェクト指向を使いこなせていないのがよく分かった。 設計ばかりは数をこなすしかないよ、と優しくアドバイスしてもらっているけれど、何とかしなくては。
DDDをもっと理解していけば何か見えてくるような気がしているので勉強のモチベが上がっている。

思ったより調べてなかった

今日調べたことはあまりなかった。 なんか調べたような気がしたけど忘れてしまった。 はてなブログのアプリが結構便利なので、休み時間とかにメモるようにしておこう。

毎日投稿している人すごすぎ

今日は飲み会があったので記事書くの大変でした。あきらめようかと思ったけど踏ん張りました。 日に日に内容が薄くなっていくのを実感。

今日は1時間~