wrongwrongな開発日記

しんまいさんの忘備録

【プログラミング】JetBrains IDEでvueファイルを編集しているときに固まる問題への対処

TL;DR

  • Intellij IDEA 2019.3で、大きめのvueファイルを編集するとハングアップするようになった
  • ランタイムをJDK8系からJDK11系に変更したところ症状が抑制された
  • 原因がJDK依存の問題か、JDK変更による処理効率アップかは不明

問題

Intellij IDEA 2019.3でソースの編集中にハングアップするという状況が度々(しかも段々悪化する形で)発生して困っていました。
以下の手順でthreadDumpを調べた所、どうもフリーズが発生するのはvueファイルの編集時のようでした。

対処

Intellij IDEA 2019.2系で日本語入力が不安定になる問題に絡めて、IDEAのランタイムをJDK8系にしていたことを思い出しました。

ここで、互換性問題や処理効率の向上を期待して、ランタイムをJDK11系にすることにしました。
変更は以下の手順で行いました。

結果

一応症状は落ち着きました。
原因に関しては詳しく調査しませんでしたが、一旦落ち着いているのでこれ以上の調査はしません。

Qiitaを始めてから1年で書いた80本弱の記事を振り返る

この記事はMicroAd Advent Calendar 2019の23日目の記事です。

目次

前書き

f:id:wrongwrongwrongwrong163377:20191222012017p:plain

自分は2018年12月からQiitaを始め、そこから1年の間に80本弱の記事を書きました。
この記事では、1年間で書いた記事の中から自信の有るものを、記事を書いた背景とともに4本選んで紹介したいと思います。

最初はQiitaに投稿しようかと思っていましたが、若干趣旨が違う気もしたのではてなで投稿します。

紹介は時系列順です。

【Kotlin】アノテーションを自作する【SpringBoot】(2018年12月4日)

KotlinBeanValidationのバリデーターを自作するという記事です。

qiita.com

SpringBoot(BeanValidation)のアノテーションKotlinで作れるかな?」という疑問を検索したところ、やり方が全く引っかからず、唯一引っかかった内容も正しいとは言えなかったため執筆しました。
今読み返すと多少の稚拙さを感じますが、それでも検索で一番上に出るなど誰かの役に立っているんじゃないかなあと思っています。

この記事は元々Qiitaに初めて投稿した【Kotlin】バリデーションの書き方の基礎【SpringBoot】と合わせて書いていた記事で、長くなったから分割したという経緯が有ります。
なので、初めてQiita向けに書いた記事としても思い入れがあります。

【SpringBoot】ファイルとその他データを同時にPostする【Axios】(2019年2月1日)

SpringBootで、複数のファイルやJSON等のデータを同時にPOSTし、かつバリデーション結果をBindingResultに格納するという記事です。

qiita.com

この記事を書いた背景は、以下の要件を達成しようと考えたためです。

  1. ファイルとJSONを同時にPOSTしたい
  2. POSTにかかる時間は最小限に抑えたい
  3. POSTされた結果をバリデーションしたい

1に関してはBase64エンコードで解決できる感も有りますが、特に大きなファイルになった場合、データ量が1.4倍弱になるという点で2が満たせなくなります。
ということでMultipartFileJSONをエンドポイントで同時に受け取る方法を探しましたが、検索しても全く引っかからなかったため執筆しました。

これができなければサーバに無理やり状態を持たせるようなやり方をする必要が有るため、有用な記事になっているかなと思っています。
自信に反していいね数が伸びないのが辛い所ですが……。

3に関しては、MultipartFileJSONをエンドポイントで同時に受け取ることができれば問題なく動く内容です。

また、この記事の応用として、【SpringBoot】ファイルの配列/リストとその他データを同時にPOSTする【Axios】という記事も書きました。

補足

MultipartFileJSONをエンドポイントで同時に受け取る場合、フォームはともかくファイルに関してはバリデーションができません。 ということで、受け取ったファイルとフォームをバリデーション用のオブジェクトにマップした上で【SpringBoot】バリデーション(@Validated / @Valid)を任意のタイミングで動かす【BeanValidation】の方法でバリデーションしてやるのが良いと今では思っています。

【Git】GUIツールGitKrakenで気に入っている3つのポイント(2019年9月30日)

自分が長年お世話になっているGitKrakenのお気に入りポイントの紹介記事です。

qiita.com

自分が書いた記事の中で初めてバズった記事で、Qiitaの日間ランキングにも載ることができました。
どうでもいいことですが、実はこの記事は会社の技術ブログで公開する予定だったもので、諸事情でQiitaに投稿したらバズったという経緯が有ります。

学生時代から使っているツールだったので、それを広めることができたのは嬉しかったです。
アドベントカレンダーで3本位書けるだけのネタは有り、本当はそれを書きたかったのですが、仕事が忙しすぎて書けなかったのが残念です。

一応明日のアドベントカレンダーに関してはGitKrakenネタで書くつもりで、20191224T1200-1200(ISO 8601)目指して執筆を進めています。

Java】拡張for文、forEach文の変数をimmutableにする(2019年10月2日)

タイトル通り、拡張for文、forEach文の変数をimmutableにするという記事です。

qiita.com

Javaの拡張for文、forEach文の変数(ラムダの引数)はmutableだったため、これをimmutableにできないかなということで執筆しました。

執筆後に間違いを指摘するコメントを頂いて書き直しが発生したという経緯が有ります。
個人的に、記事内容に関して大幅な間違いを指摘して頂いたのは初めてのことで、アウトプットにそういった知識の共有を求めていたこともあり、非常に嬉しかった覚えがあります(間違いを記事にしてしまったことに関しては申し訳ありませんでした、、、)。

特に実用性の有る内容とは言い難いですが、思い入れのある記事ということで紹介します。

補足

【Kotlin】for文、forEach文のインデックス(に限らずラムダの引数)はimmutableという記事も書きました。
実用面で言うと、Javaimmutableにすることを重視するとどんどんダサくなっていくのに対して、Kotlinでは最初からスマートな辺りがいいですね。

あとがき

ブログ本数で言うと学生時代は年100本程度書いていたので、それに比べると就職してからの1年でアウトプットのペースは落ちたかなと思います。

振り返ってみると今年は業務が物凄く忙しく、ブログの内容も個人開発というよりは業務で扱っている内容が多かったので、来年はもう少し自分で興味を持って開発や探求をし、その上で記事を書きたいという思いがあります。
また、自分のチームでは10月よりKotlinを導入しているので、業務由来に関してはJavaよりKotlinの記事を増やしていきたいですね。

来年も目標は80記事ということで、この記事を終わりにします。
今年も残り少し、皆様良いお年を~。

【Kotlin】ありえないエラーが出てハマった話【BeanValidation】

以下のように、「エラー条件を満たした場合、値をメッセージに入れて返す」的な処理をクラス内に実装していたところ、通常では考えられないバグが出てハマりました。

@Null(message = "\${validatedValue}は異常値です。")
fun getHoge(): String? = when (cond) {
    true -> hoge.value
    false -> null
}

エラー内容

エラー内容は以下の通りです。

  • condを満たしていないのにアノテーションが反応する
  • ${validatedValue}に入る値がhoge.valueじゃない(バリデーション対象オブジェクトのクラス名が入っていた)

対処法

メソッド定義の順番を変えた所治りました。

原因の考察

SpringBootValidatorKotlinコンパイル結果等々絡む要素が多すぎて特定はできませんでした。
一応デコンパイル結果も見ましたが、特に何も問題無いように見えました。

同名のプライベートフィールドやら拡張関数やら色々と入っているファイルだったので、Kotlinによるゲッター生成関連のどこかでコンパイルが壊れるのかなと思っています。

【日記】はじめてのBuzzり

自分の書いた以下の記事がBuzzったので感想を書きます。

qiita.com

何故バズったか

多分やめ太郎さんに拡散していただいたことが大きいと思います。
このおかげでGitKrakenを多くの方に知っていただけました、ありがとうございました。

Contribution数がすごい伸びる

9/30の公開からランキングから外れる10/4朝までの間で101いいねも貰いました。
この記事を除いて1年で貯めたがContributionが150弱だったことを考えると凄まじい数です。

10月2日の朝起きた時には46とか通知が溜まっていてびっくりしました。
スクショ撮ってなかったり、99+まで貯めたりしなかったのはちょっともったいなかったですね……。

日中もQiitaを確認する度に通知が来ていて、「通知が壊れるとはこういう感覚か……」などと知ったような気分でした。
千とかバズる方々の通知欄はヤバそうですね。

実はQiita向けに書いた内容じゃなかった

この記事は、元は会社の技術ブログ用の内容でしたが、社内調整の結果公開が先になりそうで、バージョンアップも頻繁に来ていたため、取り下げて個人で公開したという経緯が有りました。
個人的には会社のブログでバズってくれた方が嬉しいかなとか色々思いましたが、それとは別にいい意味でバズると気分がいいものですね。

最後に

GitKrakenは2016年末からずっと使っている思い入れのあるツールであるため、この記事がAxosoftさんとGitKrakenに対してプラスに働いてくれたら嬉しく思います。
記事の末尾に書いたとおり、この記事では語り尽くせない良さが沢山あるので、是非皆さんもGitKrakenを使ってみて頂けるとありがたいです。

【日記】DDD的な設計完全に理解したメモ【プログラミング】

マサカリ避け

本読んでないです。
経験則です。
DDDチョットデキル人になりたいです。

前書き

「大量の相関チェック(しかもDBアクセスなど層をまたぐ処理や複数オブジェクト間の相関チェックを含む)とその後の登録が発生する状況」を想定して書きます。
言語はJava(SpringBoot)想定です。

最近作っているプロダクトで、DDD的な考えに触れて自分が考えたことを設計に取り込んだ経験から書きます。

ドメインを見極める

ドメインとは、複雑になりそうな処理内容を切り出したものです。
想定した状況の場合、まずバリデーション処理は物凄く複雑になるでしょう。

この「複雑な何か」、「まともにやりあったら複雑すぎてコードと自分が爆発四散しそうなもの」がドメインです。
ここではドメインが明確になったものとして話を続けます(でもDDDで一番むずかしいのはドメインの見極めだとは思います)。

実現する

次に実際の処理の作り方です。

まず書いてみる

どんな処理であっても、何を実現するのか、そのために何が必要なのかを理解するために努力していれば、「何かこうやったらうまくいきそう」という想像ができると思います。
そのぼんやりした想像を、図に書いたり、コードに書いたり、何でもいいから書き出してみて、その上で分からないことが有れば聞いたりはっきりさせていきながら書いたり捨てたりしていくのが良いでしょう。
そうして「処理とフィールドの塊」を作っていきます。

今回はドメインの持つべきフィールドの内容が以下の3クラスにまとまったものとして話を進めます(ゲッターや内部処理等は省略)。
内容は、DomainRootがDomainChildとDomainNodeを持っているというものです。

public class DomainRoot {
    private final DomainChild domainChild;
    private final DomainNode domainNode;
}
public class DomainChild {
    private final ChildValueObject childValueObject;
}
public class DomainNode {
    private final NodeValueObject nodeValueObject;
}

そうして全体の構造をはっきりさせていくと、今度はドメイン内部で用いる処理が3種類に分けられるようになります。

  • 単体のオブジェクト内で処理が完結する内容
  • DomainRoot内の情報をDomainChildやDomainNodeが必要とする内容
  • レイヤーをまたぎ、ドメインオブジェクト外に処理を書く必要がある内容

この内、単体のオブジェクト内で完結しない内容について具体的な実装のコツを書きます。

単体のオブジェクト内で完結しない内容をどう書くか

個人的には、以下3つの方法があると思っています。

  • 関数型インターフェースで処理を受け取る
  • インターフェースを用意してその実装を受け取る
  • abstractクラスを作り、その実装を受け取る

この内まず試すべきなのが関数型インターフェースで処理を受け取る方法で、数が多かったり、上の方のクラスで継承するなどの理由が有ればインターフェースを用意してその実装を受け取る方法に順次シフトするのが良いと思います。

abstractクラスを使うやり方は、Javaでは多重継承ができないなどの制約が有り、そもそも要求する内容はフィールド等を要求しないため、やらない方がいいと思います。

DomainRoot内の情報をDomainChildやDomainNodeが必要とする内容

DomainChild.childValueObjectの検証にDomainNode.nodeValueObjectの内容が必要な場合を、 関数型インターフェースで処理を受け取る例で書きます。

public class DomainChild {
    private final ChildValueObject childValueObject;
    // 外部に公開しないように保持する
    // この関数をコンストラクタで渡してもらう
    private final Predicate<ChildValueObject> predicate;

    // バリデーション関数
    private boolean isValid() {
        return predicate.test(childValueObject);
    }
}

ここで要求される関数を、DomainRoot側では以下のように実装します。

public class DomainRoot {
    private final DomainChild domainChild;
    private final DomainNode domainNode;

    public DomainRoot() {
        // 引数や途中の処理は省略

        this.domainChild = new DomainChild(
                childValueObject,
                it -> /* domainNodeの絡むような相関チェック */;
        )
    }
}

重要なのは、外の内容を必要とする(DomainChild)側は「引数を渡したら検証結果が返ってくる」ような関数を要求することです。
これによって、DomailChildは外の処理を知らずにそれが正しいかを検証することができるようになります。
また、この相関チェックは本質的にルートが知っておくべき処理なので、それをDomainRootに書くこともできています。

レイヤーをまたぎ、ドメインオブジェクト外に処理を書く必要がある内容

レイヤーをまたぎ、ドメインオブジェクト外に処理を書く必要がある内容を、インターフェースを用意してその実装を受け取る例で書きます。

具体的には、以下のように実装します(前節で追記した内容は書くと邪魔になるので排除しています)。

public class DomainChild {
    public interface Delegates {
        HogeDto getHogeDto(Integer childId);
    }

    private final Delegates delegates; // 移譲はコンストラクタで受け取る
    private final ChildValueObject childValueObject;
}
public class DomainNode {
    public interface Delegates {
        FugaDto getFugaDto(Integer nodeId);
    }

    private final Delegates delegates; // 移譲はコンストラクタで受け取る
    private final NodeValueObject nodeValueObject;
}
public class DomainRoot {
    // ルート側では特にインターフェースを要求しなかった場合を想定
    public interface Delegates extends DomainChild.Delegates, DomainNode.Delegates {
    }

    private final DomainChild domainChild;
    private final DomainNode domainNode;

    public DomainRoot(Delegates delegates) {
        domainChild = new /* delegatesを渡す */;
        domainNode = new /* delegatesを渡す */;
    }
}

これによって、「ドメインに対してその他処理が依存している状態」を作り出すことができます。
補足として、今回は「このオブジェクトはDBから取ってくるものだ」ということを強調するために『なんたらDto』というような名前を付けていますが、これに関しては必要な情報をドメイン層に定義した上でそれをDBから取ってくるという形としなければ、「ドメインに対してその他処理が依存している状態」にはなりません。

なぜこう書くときれいだと言えるのか

ここまで長々と書いてきましたが、今書いたコツは一見するとかなり複雑なことをやっているように見えます。
なぜこう書くときれいだと言えるのか、自分なりの答えは以下3点にまとまります。

  • どのドメインオブジェクトでも「そのオブジェクトの中でやるべきこととそうでないこと」が明確に分かれている
  • どのドメインオブジェクトでもDBなど「Javaの外側の世界」/「具体的な実装」を意識せずに実装できている
  • どのドメインオブジェクトも使い方・使われ方が明示されているため、それに従うだけで処理を生やしていくことができる

細かく言い出すとキリが有りませんが、対象の処理が複雑なのにこれらが成り立っていない部分の有る設計は大体どこかで破綻すると思います。

まとめ

まとまってませんが、とりあえずこれを意識して設計することで、以下のような利点が有ると思っています。

  • 外側の変更に強いシステムを作ることができる
  • 「どこに何を書くか問題」がドメイン別に整理されることでスッキリする
  • ドメインファーストで設計することで、複雑さを切り離して楽になることができる

【Java】interfaceでinterfaceをimplementsしたかった(extendsが正しかった)話

やりたかったこと

以下のようにinterfaceが2つあるとき、この2つのinterfaceを継承したinterfaceを作ろうとしました。

public interface Interface1 {
    String hoge();
}
public interface Interface2 {
    int fuga();
}
やろうとしたこと

interfaceなので、以下のようにimplementsすればいいと考えましたが、これでは動きませんでした。

public interface Interface3 implements Interface1, Interface2 {
}
正しいやり方

extendsを指定するのが正しかったです。

public interface Interface3 extends Interface1, Interface2 {
}
public class Impl implements Interface3 {
    @Override
    public String hoge() {
        return null;
    }

    @Override
    public int fuga() {
        return 0;
    }
}

【日記】「エンジニアが不要とされる瞬間」について考えたこと【意見】

wrongwrong163377.hatenablog.com

上記記事に関して、「じゃあ未来永劫エンジニアが必要とされ続けるか」と言われるとそうでもないと思っている話を書きます。
自分は主に以下の状況でエンジニアが不要とされるだろうなと思っています。

  • 人格と社会的な不確実性まで再現するAIが出てきたとき
  • 戦争になったとき
  • 核戦争になったとき

人格と社会的な不確実性まで再現するAIが出てきたとき

これに関しては、もう人間そのものが不要になるだろうなあと思っています。

人間の有利な点はその汎化能力と言われていますが、人生を無限にエミュレートするようなことをされてしまえば、どんなこともAIには敵わなくなるでしょう。
特に机上でアレコレやるのが主な仕事となるようなエンジニアは真っ先に置き換えられてしまいそうな気がします。

ただ、これに関してはもはや人類共通の問題となってしまうので、そこまで行ったらもう諦めるしかないんじゃねとも思っています。

戦争になったとき

これについてはほぼ日本しか見ていない話です。

色々きな臭い世の中になっていますが、今の日本の状況で戦争になったとき、エンジニアの技能は全く大切にされないだろうと思っています。
第二次大戦でも重要な技能者を徴兵で溶かして兵器の生産力を下げるなんてことをやらかしていましたが、現代でもそうだろうなあという諦めが有ります。

まず上に立っている人間がIT音痴すぎるので、エンジニアという道具の用途なんて考えられないでしょう。
また、国民の方も「後ろで何やってるか分からない奴なんて前線に出したほうがいい!」という声で応えそうだなと思います。

状況が不安定になったとき、エンジニアの立場は多分弱いです。

核戦争になったとき

直接的に電子機器が壊れることもそうですし、ライブラリ・パッケージの配信システムがやられたり、クラウド環境が消し飛んだりすれば結構なエンジニアが仕事できなくなるだろうと思います。
少なくとも色んなサービスが止まることでしょう。

まあ、こんなことになればやっぱり人類共通の問題となってしまうので、そこまで行ったらもう諦めるしかないですね。

終わりに

今の世の中は物凄くきな臭いことになっていて、全方面「なんかあったら社会的にも人生的にも終わるかもなあ」で囲まれてしまっている感が有ります。
日本という国の将来に希望を見いだせないというか、人類という種の将来そのものに希望を見出せません。

宇宙植民さえ軌道に乗れば人類は未来永劫やっていけるんじゃないかと思うので、できればそういう世界線に収束して欲しいものです。