【日記】読みやすいコードについて考えたこと

読みやすいコードとは何かについて個人的に思っていることについて書きます。
前提として、黒魔術的な話や自動整形で直せるような部分には触れません。

そもそも読みやすさとは何か?

最近のコードにおける読みやすさとは「その処理によって何がどう変化するか(しないか)を予測できること」だと自分は考えています。
今時の「動的型付け辛い」だとか「強力な型システムはいいぞ」だとか「関数型プログラミングはいいぞ」の流れも結局本質はそこにあると思っています。

要するに、文法の良し悪しだとか見た目がきれいだとかいう以上に何が起きるか(起きないか)を人間が予測しやすい形になっているかの方が問題だということです。

最近の言語はいかにして読みやすさを確保するか

最近のプログラミング言語は以下のような要素を実現することで読みやすさを確保していると思っています。

  • 強力な型システム
  • スコープを強力に区切ることによる外部への影響の限定
  • mutable / immutableの徹底

逆に言うと、これらに反するようなコードの書き方はあまりよろしくないものだと解釈しています。

具体的なコードの読みやすさ

「自分ならこう解釈する」という程度の話ですが、ここまでの流れを踏まえ、Javaでの一部機能を例にどちらが良いと感じるかを書きます。

if文 vs 三項演算子

三項演算子の方がよいと考えています。

理由は、if文ではその中で一体どのような副作用が発生するか分からないのに対し、三項演算子では恐らく代入しか行われていないことが想定しやすいからです。

一時変数を置く vs 置かない

極力置かないか、置いてもスコープが限定されていて使い捨てにされるべきだと考えています。

理由は、スコープ内に変数が増えれば増えるだけ何が起きるかの予測が難しくなるからです(e.g. 再代入されたり、リストの中身が別の場所で変更されるなど)。

StreamAPIやOptionalを上手く使えば一時変数と上手く付き合うことができますし、極力宣言される一時変数は少ない方が良いでしょう。

ただし、やりすぎると実際に読みにくくなるというのは確かだと思うので、「一時変数が無く読みやすい > 一時変数が適度に有る > 一時変数が無く読みにくい > 一時変数が多い」の順で良いコードだと考えています。

for文 vs forEach文

forEach文を使うべきだと考えています。

理由は、forEach文では外部の変数が変更されない(中身が変更できることはともかく!)ということが明示されるのに対し、for文や拡張for文では外部の変数に対して変更ができるため、動作の予測が難しくなるからです。

また、インデックスを使うようなfor文に関しても、これからはIntStream等のrangeを使うことで対応ができるので、これからは余程の事情が無ければ通常のfor文を用いるべきではないと思います。

読みやすさか能力不足か

このような話題を出した時、「とは言えこの書き方は読みにくいんじゃないか?」という意見が出ることは有りますし、実際自分も「この書き方だと読みにくいんじゃないか、読みにくいなら使わない方がいいんじゃないか」と感じたことも有ります。

ただ、エンジニアになって半年以上開発を続けた結果、これはコードが読みにくいのではなく自分の能力が不足しているということなのだと解釈するようになりました。

理由は以下の3点です。

  1. 鬼強い人らが集まって決めたプログラミング言語の仕様だから嬉しさは必ず有る
  2. その嬉しさを使わなければ損をする
  3. 嬉しさを使わない理由が能力不足なら悪いのは自分

確かに新しいものを積極的に使おうと思えば覚えることは非常に多岐に渡ります。
一方、何故新しいものが追加されたかと言えばそれに嬉しさが有るからです。

少なくとも当分技術で食って行こうと思うなら、プログラミング言語に新しく追加された機能からなるべく早い時期に嬉しさを引き出そうという姿勢は必要だと思います。

とは言え既存のコードの秩序を破壊するべきなのか?

エンジニアは日々成長する生物であるため、コードを書いていく中でより良い書き方に出会うことは多々あると思いますが、その時どのタイミングでどのようにより良いコードを取り込んでいくかという話です。
これには以下3つの選択肢が有ると思います。

  1. 全面的なコードの改修を含めた対応を行う
  2. 新しいコードは原則それを用い、既存は順次改修していく
  3. それを用いない

チームで相談して1を選べるなら特に問題は有りませんが、2の選択肢を選ぶ場合既存のコードと整合性が取れなくなることについてどうするべきかという話になるでしょう。
また、それを用いると見た目がガラッと変わるため、読みにくく感じてしまう場合も有ると思います。

それでも、自分は以下3点から2の選択肢を取るべきだと思います。

  • 読み書きしていけば文法には慣れる
  • 実装レベルでの文法ブレはそこまで重大な問題ではない
  • 直していった方が将来的なバグを防げる

まとめ

読みやすいコードとそれを書いていく上での心構え的な部分をまとめました。

かなり原理主義的な意見だという自覚は有りますが、個人的にはこのスタンスでやっていくことが結局コード品質の向上につながるだろうと思っています。

【日記】エンジニアの自分が"床上手な処女"に求める技術的スキル

「即戦力学生」という存在が目立っていたり、企業側もそんな存在を求めていたりする中で、エンジニアの自分が「エンジニアとしてこんなスキルを持った人間と働きたいな」と思っているスキル3つをまとめます。

タイトルについて

『床上手な処女』というのは下衆な表現だと思いますが、そもそも学生に即戦力性を求めていることそのものが状況として下衆っぽいよなと思うので、敢えてこの言葉を使います。

「そもそもお前そんな求められるぐらい実力有るんだっけ」とか言われると何も言い返せませんが、それを妄想する位は許されるといいな……。

1. Git / GitHubを用いた開発スキル

モダンな開発をやっている会社ではほぼ確実にGit / GitHubを使って開発を進めます*1
どの言語、どのフレームワーク、どんな環境であったとしても共通でほぼ確実に使います。

コードを書く時Gitで詰まるのはかなり大変です。
詰まっている間はアウトプットが出ませんし、他にも分からないことだらけなのにGitで詰まるというのは焦ります。
また、1コミットがデカかったり、1つの内容が2コミットに分かれていたり、プルリクの単位が大きすぎたり、チーム内の決め事が守られていなかったり、Gitを使いこなせないと他メンバーに迷惑をかけることにもなります。

また、ニーズ抜きにGitはとても便利なツールなので、使いこなしてる人の方がアウトプットが出るだろうなという期待も有ります。

求めるレベル

GUICUI問わず、以下の操作が呼吸のようにできれば十分レベルが高いなと思います。

  • 適切な単位でbranchを切ってcommitしてpushしてプルリクが出せる
  • 長いブランチをコミットやファイル単位で分解して複数のブランチに分けられる(cherry-picなどを問題なく用いられる)
  • rebase, reset, revertが問題無くできる

2. IDEを用いた開発スキル

現在のIDEには、以下のような機能が当たり前に付いています。

  • コード補完
  • よりよいコードの提案
  • コンパイルエラーをコンパイル前に表示
  • ソースの定義に移動
  • ソースが利用されている場所に移動
  • 行単位で簡単にデバッグ
  • Gitを絡めたコードの変更箇所のハイライト
  • etc...

これらの機能を使わずに開発をしても能率が上がりませんし、コードの品質も低下するため、最近では単純なプログラミングだけでなくIDEをどれぐらい使いこなせるかが生産性に大きく寄与するようになっています。

個人的には、Inellij系(JetBrains製)のIDEで開発している人なら、別言語だろうが作業するプラットフォームが変わろうがそれほど影響なくやっていけるだろうということで、バリューが高いなと思っています。
また、IDEでなくてもIDEと同じことができるというのは確かに有りますが、その環境構築の手間や環境依存を考えると今の時代はIDEに甘えた方がいいんじゃないかとも思っています。

求めるレベル

以下ができれば十分レベルが高いなと思います。

  • コード補完やより良いコードへの置換を使いこなせる
  • ブレークポイントを貼って行単位でデバッグできる
  • ソース定義・利用箇所への移動を使いこなし、ライブラリから必要なコードを持ってくることまでできる
  • プラグインを導入するなどしてIDEをカスタマイズできる

3. プロジェクトに区切りを付けるスキル

どんな素晴らしい設計であっても、どんな綺麗なコードであっても、リリースしなければ価値を生みません。
設計もコードも綺麗にすべきですが、そのために時間は必要です。
一方、そのような時間を取るだけの余裕が必ずしも有るとは限りません。

検討の死角は大概やってから気付くもので、好奇心やプライドより実利を優先するという判断力は必ず必要になってきます。

あるいは、その問題を放置することが大きな問題になるようであれば、目先の利益を捨ててでもその問題に対処する必要があるかもしれません。
その判断をチームで共有し、実行するためには、どちらの道をとった場合にどのようなメリットとデメリットが有るかを定量的に示す必要があるでしょう。

プロジェクトをどこで区切るかを決めていくためには、自分の直感がいかに正しいかを検証し例示することが必要になってきます。

自分がどう物を作ることが組織に対してメリットを生むかを判断する能力は実務経験を積むことで養われるものだと思いますが、だからこそ学生の内からこのようなスキルを研いでいる人と働けたらいいなと思います。

求めるレベル

個人・複数人やプログラミングだったかを問わず、期限があったり、お金が絡むような状況でプロジェクトを進めた経験が有るとレベル高いなと思います。
その内容が月単位など長期間で取り組んだものであればより凄いなと思います。

補足: 「どんな技術を使えるべきか」という問いに対して

あくまで個人的な意見ですが、学生の間は「どんな技術を使えるべきか」という問いを社会人に投げても無駄なんじゃないかと考えています。

理由は2つ有ります。
1つは、企業からすれば「自社で使っている技術 or バズってる技術」位しか提示しようが無いことです。
もう1つは場で勉強すれば何だってできるんだから、勉強の効率を上げたり本質的な内容に集中するためのスキルを磨いた方が長いこと食っていけるだろうと思っているからです。
意識の高いワードを使うなら"本質的な人間力の方が大事"ってやつです。

また、上に書いたようなスキルを得ているなら、必ず難しい開発に立ち向かったことが有るはずなので、今やっていることがどれだけマイナーなことであったとしても、その時点で技術力に不安は無いなと感じます。

最後に

ここまで書いたスキルは学校ではやらないような開発、即ち複数人か大規模か、その両方な開発をする上で必要になるスキルであって、学校に居たからって身に付くものではないなと学生生活を振り返って思います。
また、こういった内容はメンターが付いた状態で作業をしてやっと身に付くものが多いと感じるので、特に地方の学生でこの辺りのスキルを養うような機会が得られる確率はかなり低いでしょう。
だからこそ"床上手な処女"という訳ですね。

 書いてみて、「こんな社会人みたいな人材であることを学生に求めるのは下衆な考えだ」と改めて思いますが、とは言えレベルの高い・会社に貢献してくれそうな人材を探せばまず間違いなくこんな感じの属性が入って来ると思うので、どうにもならないなと悲しい気分になってきます。

学生の内から実績を求められるっていうのは何だかなあ……。
というか自分も今できてないようなことまで書いてるし……。

纏まらなくなったのでここで切ります。

こんな駄文を長時間読んでいただいてありがとうございました。

*1:GitHubに関しては、GitLabだったりGitHub Enterpriseだったりで差異が有るでしょうが、バージョン管理ツールは基本Gitでしょう。

【ASP.Net Core】@Html.TextAreaForの初期値が入らなくて詰まった話

状況

TextAreaForModelを正しく指定しているにも関わらず初期値が入らない状況になりました。

原因

TextAreaForを追加しようとする前は、ViewData経由でcshtml側に値を渡してバインドし、バインドされた値によってModelが初期化されるという構造になっており、Get時にModelは初期化していませんでした。
一方、TextAreaForは直にModelを参照して自身を初期化しようとします。

つまり、TextAreaForは初期化されていないModelを参照しようとしていたために初期値が入らなかったというのが原因です。

対処

Modelを初期化して初期値を代入すればできました。
というか、型的な意味でもViewDataを使わない形式にしておいた方が良かったと思います。

【HTML】Google Chart APIでQRコードを生成して表示する

やり方

以下のAPIに対してQRコードにしたいURLを指定することで、簡単にQRコードを生成することができます。

http://chart.apis.google.com/chart?chs=320x320&cht=qr&chl=/* QRコードにしたいURL */

例えば、このブログのブログトップを指定すると以下のようになります。
http://chart.apis.google.com/chart?chs=320x320&cht=qr&chl=https://wrongwrong163377.hatenablog.com/

詳細設定

サイズや余白といった設定は以下に詳しいです。 www.atmarkit.co.jp

応用

以下のようにimgタグのsrcに指定することで、QRコードを簡単にHTMLに埋め込むことができます。

<img
  src="http://chart.apis.google.com/chart?chs=320x320&cht=qr&chl=/* URL */"
  alt="QRコード"
/>

【SpringBoot】vuejs-datepickerで取得した日時をPOSTするとサーバーサイドで読んだ時に1日前になる問題が発生した【Vue.js】

やりたかったこと

  • vuejs-datepickerでPOSTした日時から、サーバーサイドで日付を取得する

問題の概要

  • vuejs-datepickerタイムゾーンまで含めてデータを出力する
  • Jacksonはフォーマット設定をしなければ受け取った日時をGMT基準(=日本時間-9時間)に変換し、それをLocalDateに変換する
  • このため、サーバーサイドが受け取ったLocalDateが日本時間の9時間前(= 時間によっては昨日)になった

補足

  • 自分のやっていた環境では、vuejs-datepickerの出力するデフォルト時間は日本時間で9時に設定されており、サーバーサイドで時間は利用していなかった
  • このため、日本時間で9時未満が出力されるような特定の操作をしなければ症状が再現できなかった

対策

  • 本来はJacksonが解釈する日時のフォーマットを決定し、設定しておくべき
  • 日付しか必要なく、応急的な対処でよいのであれば、時間情報を無くして(e.g. ハイフン区切り: 2019-01-01)POSTすればズレることは無くなる

結論

  • 日時扱うときは日時表現のフォーマットや設定にまで気を配った方がよい

【Java】最近やっているプロジェクトで後悔していること5点【プログラミング】

Java8でプロジェクトをやっていて後悔していることを5点挙げます。 上から後悔している順です。

nullを返すな、Optionalを使え

文字通りなんですが、null が絡むと何が返ってくるのか分からない状態になるのでOptional使った方がいいです。
特にnullを返しがちなものをUtilにしてしまったのは深い後悔が有ります。

var / valは使った方がよい

lombokvar / valを想定しています。
lombokに依存してしまうというのはそうなんですが、省力化や可読性の高さよる開発効率の向上を考えれば、最初に開発するときはvar / valを使った方が結果としてマシなコードになりやすいと考えています。

(もっと言うならKotlinなどオルトJavaのがプロダクトは綺麗になるなとは思いますが、障壁の厚さも、、、)

オブジェクト名は冗長なぐらいの命名にした方がよい

後からオブジェクトが増えたとき、一体どんな役割を持っているか本当に分からなくなったので、冗長に感じてももっと具体的な命名をすればよかったです。

Lintはチェックルールよりコーディング規約を変更すべきだった

Lint関連の修正はお願いするのも実行するのも手間だったので、ツール側に全部合わせた方が楽でした。
その辺が負担になると機械の奴隷感が出てくるので、何かしらのデフォルトを使った方がいいんじゃないかと思っています。

引数に取るならListよりCollection

Listにしてて困ることが少ないのはそうなんですが、Setを入れたいときに困ったりするんですよね。 Collectionを引数に取って困ることはあまり無いと思うので、やっておくとスマートになったかなと思います。

【プログラミング】好きなインデント、嫌いなインデント【日記】

インデント数や改行のやり方について、自分の好みを書きます。
言語はJava想定ですが、別言語でも基本的な好みは同じです(IDEは当然使うものとします)。

はじめに

好みとは言いますが、基本的に「合理的と感じるか感じないか」が根拠です(あ、この言い回しオタクっぽい)。

そもそもの話

ぶっちゃけどのフォーマットでも利点と欠点は有ると思います。
特に最近はエディタの整形機能やネスト量の表示機能が優秀なので、「コードを作成する/エディタ上で読む」という部分に着目すれば、どのやり方もそう大きくは変わらないと思います。

インデント数

インデント設定というと、基本的に以下3通りに分けられると思います。

  • 2スペース
  • 4スペース
  • Tab

個人的にはこの内で2スペースインデントが好きです。
2スペースインデントの利点は話し尽くされていると思いますが、単純なコードの読みやすさという観点からはズレた部分で語っていきます。

4スペース対2スペース

2スペースインデントを推す理由は、エディタ外での読みやすさが変わるからです。

例えばSlackに投稿する場合やブログやQiitaに記事を作る場合、読みやすい横幅はエディタよりも小さくなるため、4スペースインデントではしばしば不都合があります。
この傾向は、スマホなどの環境でコードを読む時により顕著です。
コード部分が横にスクロールしてくれるならまだいい方で、改行折り返しされてしまうと構造が崩れてもう読めません。

エンジニアにアウトプットが推奨される昨今、エディタ外での読みやすさを考えてコーディングするというのはトレンドになって欲しいなーと思います(とか言いつつ4スペースインデントで記事を量産してるけど)。

Tabインデント

私的にこのような話をしていたところ、「Tabインデントにして幅は個人で設定できるようにすればいいんじゃないか」という意見を頂きましたが、個人的にTabインデントは好きじゃないです。

理由は以下の3点です。

  • 環境によって表示が異なる場合がある
  • 環境ごとに表示設定しなければならず面倒(最悪設定できない場合もありうる)
  • Tabと半角スペースが混じっても見分けられないため、表示が崩れる場合がある

半角スペースをそのまま打つインデントであれば、どんな環境でもある程度読める状態でコードが出ますが、Tabの場合は8文字分のスペースで表示されてしまう場合が有るなど、状況によって設定の修正が必要となります。場合によってはその設定が用意されていないかもしれません。
また、半角スペースとTabとが混じった場合も面倒です。混じっておかしくなる位なら、Tabは入力禁止としたほうが合理的だと思います。

ということで、Tabインデントは好きじゃないです。

改行の方式

大きく、ブロックの改行と引数の改行について書きます。

ブロックの改行

大体以下2種類に分けられると思いますが、個人的に前者のほうが好きです。

if (hoge) {

}
if (hoge)
{

}

理由

以下2点から、現状の環境では「改行量が多い=良くないこと」だと感じるからです。

  • IDEの補助線等の機能から見やすさに殆ど差がない
  • 1画面により多くの情報を表示できたほうがコード間を行き来する回数が減る分可読性が上がる(コード間の物理的距離が離れると可読性が下がる)

特に後者は縦に長すぎる関数の可読性が低い辺りから明らかじゃないかと思います。

引数の改行の方式

引数の改行は、以下2つの方式を知っています。
前者はJavaDocの表示などでよく見るパターンですが、個人的には後者のほうが好きです。

void func(int a,
          int b) {

}
void func(
    int a,
    int b
) {

}

理由

前者では以下3点辛さが有ることが理由です。

  • 引数以前に最長で「インデント + 修飾子 + 戻り値の型 + 関数名」となるため、これらが物凄く長くなった場合に後続の引数を書きにくい
  • メソッド引数を閉じる部分は最長で「アノテーション + 引数の型 + 引数名 + throws句」となるため、メソッド引数開始部分までが長くなると書きにくい
  • (エディタ外で書く時)等幅じゃないフォントだと調整が難しい

極端な例では以下のようになります。

protected static final TypeOfHogerara MethodNameOfHugaGaga(ArgumentTypeOfFooFoo argumentTypeOfFooFoo,
                                                           @AnnotationOfPiyoPiyo(value = "ValueValue") ArgumentTypeOfBarBar argumentTypeOfBarBar) throws ExceptionTypeOfBuzzBuzz {
protected static final TypeOfHogerara MethodNameOfHugaGaga(
    ArgumentTypeOfFooFoo argumentTypeOfFooFoo,
    @AnnotationOfPiyoPiyo(value = "ValueValue") ArgumentTypeOfBarBar argumentTypeOfBarBar
) throws ExceptionTypeOfBuzzBuzz {

結論

ここまで長々書いてきましたが、最終的にはチーム内で定めた自動整形ルールに任せるのが一番だと思います。
インデントやらは本質的な作業ではないので、整形はプログラムに任せて人間はプログラミングに集中すべきでしょう。

ただ、最近のモダンな言語はどんどんコード中の情報密度が上がっていると感じるので、その延長線上で「大量の改行が入るだとか、大量のインデントが入るスタイルというのは環境に適していないんじゃないかなあ」とは感じています。
C言語の登場以来50年弱が経過した今、慣習で残っているからと言ってそのフォーマットが可読性に対して合理的かというのはちょっと疑ってかかるべきなんじゃないかなあ、とも。

まとまってませんがこの辺りで終わります。