聞こえないJavaエンジニアが適当に書き連ねていく

つらつらとメモしたり日頃の溜まっている想いを吐き出す場所です。

Effective Java 第3版を買いました

Effective Java 第3版を溜まってた楽天ポイントで買ったので実質無料でゲットなのです。

f:id:su_zu_ki_1010:20181030143926j:image

1ページめくるたびに、わかるような、わからないような、そんな気分を味わう。でも、それでいいのです。載っている90個全てがすぐに完全に理解できるわけがないので、実務と読書を繰り返してある日ストンと腑に落ちる日が来ればいいんだろうなー、と思いながら睡魔に耐えてまたページをめくる、そんな日々。

第2版も出版されてからかなり時間が経っているのに、今でも読み返すと新しい気づきがある。

第3版も一度、通して読み終えたら気になる部分を再度読み返して行くことで理解を深める、そんな本ですね。

Java初学者にはオススメ出来なくて、むしろ、Javaは完全にマスターしました!という人が読むべき本。

Spring Boot 2.0.6で日時を固定したテストを書きたいとき

断り書き

個人的な覚書です。 バージョンアップで動かなくなる可能性があるので検索でヒットして、真似る時は気を付けてください。

前提

以下に書かれている記述が動いた時のバージョンは以下の通り。

  • Java 1.8
  • Spring boot 2.0.6
  • JUnit Platform 1.3.1
  • JUnit Jupiter 5.1.1 (Spring boot のtesterデフォルト)
  • JUnit Vintage 5.1.1 (Spring boot のtesterデフォルト)
  • Jmockit 1.43

やりたいこと

プログラム内で行っている、システム日付取得の部分をJUnitでのテストの時は固定の日時にしたい。 ※時間に応じて挙動が変わる個所があるため。

試したこと

ダメだったもの

最初はここに書かれている内容を真似して書いたらうまくいった。

JMockit を使用して LocalDateTime.now() で指定した日時を取得する. · GitHub

しかし、実はJmockitのバージョンがかなり古いものを使っていた。(どこかの記述をコピペしたのが原因)
諸事情でIDEを変えた時に、JMockitのバージョンも上げたら java.lang.ExceptionInInitializerError を吐いてしまった…。
調べると、JMockitのバージョンアップで今まで書けていた内容がNGになった模様。

うまくいったもの

仕方ないので再度調べ直したら、以下のサイトがヒットした。

sebastiankoltun-blog.com

ここに書かれていることを参考に、書き直したら日時を固定できるようになった。

現在日時を返すだけのfactoryクラスを作る。

import java.time.LocalDateTime;

import org.springframework.stereotype.Component;

@Component
public class TimeFactory {

    public LocalDateTime now() {
        return LocalDateTime.now();
    }

}

呼び出す側は、TimeFactory.java をインジェクションする。

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

import org.springframework.stereotype.Component;

@Component
public class TimeFactoryCall {

    private TimeFactory clock;
    
    public TimeFactoryCall(TimeFactory factory) {
        this.clock = factory;
    }
    
    public String get() {
        
        LocalDateTime date = clock.now();
        return date.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"));
        
    }
    
}

テストプログラムはこんな感じ。

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;

import java.time.LocalDateTime;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@ExtendWith(SpringExtension.class)
@SpringBootTest
class TimeFactoryCallTest {

    @MockBean
    private TimeFactory clock;

    @Test
    void test() {

        LocalDateTime TEST = LocalDateTime.of(2018, 10, 16, 14, 23, 59);
        when(clock.now()).thenReturn(TEST);

        TimeFactoryCall call = new TimeFactoryCall(clock);

        assertEquals(call.get(), "2018/10/16 14:23:59");

    }
}

他に参考にしたサイト

qiita.com

“ゴミ記事” について考えてみた

最近、エンジニアはブログを書けとかゴミ記事は書くな、という話題をシステム開発界隈で見かけるので個人的に思うことを書いてみる。

 

まず、ブログを書けという論調、これには同意する。個人的なメモでも、1ヶ月後の自分、1年後の自分にとって役にたつことがある。

ただし、その場合は未来の自分が検索ワードに使いそうな言葉を必ず書いておくこと。今は自明な言葉でも、未来の自分は忘れている可能性が大だから。

それに、やってみたときのバージョン情報も必ず載せること。バージョンによって動いたり動かなかったりすることがあるので、このバージョンで動いたという事実を載せることは大事。

 

次に、ゴミ記事は書くなという論調。これも気持ちとしては分からなくも無い。自分も検索してヒットしたものが求めていなかった内容だった時は一瞬空を仰ぐし、ため息も出てしまうかもしれない。

でも、自分にとってゴミ記事でも、他の人にとってはお宝かもしれない。

やってみた記事であれば、自分は動かなかった内容がその人は動いているわけで、何が違うのか?を確認することが出来る。逆に、もしかしたら当時は動いたけどバージョンアップで動かなくなった、ということがわかるかもしれない。

やってみたけど動かなかった、という記事もゴミ扱いされるが、ちょっと待ってほしい。

まず、動かなかった、をそのまま信じてしまうのは勿体ない。バージョンアップで動くようになっているかもしれないから。

同じバージョンだとしたら、あなたがやろうとしていることは今のバージョンでは出来ない、という事実がわかるので諦めるきっかけになるのではないか?

 

あとは、その記事を書く場所は適切な場所なのか?を考えてみる必要があると思っている。

自分のブログなら何を書いてもいいと思うが、情報共有系のサイトに書く時はそのサイトの指針にあっているかをちゃんと考えないといけない。

 

まぁそんなことをポンコツエンジニアはいろいろ読みながら考えたよ、っていうね。

 

 

今更ながらJavaでプレミアムフライデーを求めるロジックを考えた

www.waenavi.com これを読んで、Javaだとどうやって書けばいいか考えてみた。

まず、Java8以降は日付は LocalDate を使うようなのでAPIを読む。

LocalDate (Java Platform SE 8)

月末日をまず求めて、その日が金曜日じゃなかったら1日ずつ遡って曜日をチェックしていけばいいかな、と思いながら last をキーワードにしてページ内を検索してみる。

result = localDate.with(JULY).with(lastDayOfMonth());

という一文が出てくる。 これはいったい?と思い、ちょっとページを上に動かすと with というメソッドの説明だった。

https://docs.oracle.com/javase/jp/8/docs/api/java/time/LocalDate.html#with-java.time.temporal.TemporalAdjuster-

説明文を読んでみると、

一般的な調整の選択は、TemporalAdjustersで指定します。

と書かれており、TemporalAdjusters へのリンクが貼られている。

TemporalAdjusters (Java Platform SE 8)

リンクをクリックして、どんなメソッドがあるのかなと眺めると

lastInMonth(DayOfWeek dayOfWeek) 一致する最後の曜日を持つ同じ月の新しい日付を返す、月の最終アジャスタを返します。

という今回の用途にバリバリ使えそうなメソッドの説明が載っている。

https://docs.oracle.com/javase/jp/8/docs/api/java/time/temporal/TemporalAdjusters.html#lastInMonth-java.time.DayOfWeek-

どうやらこれを使えば欲しいものが求められそう。

念のため、DayOfWeek へのリンクもクリックしてどんな定義があるのか眺めてみる。

DayOfWeek (Java Platform SE 8)

FRIDAY 「曜日」金曜日のシングルトン・インスタンス

という記述が確認出来たので、金曜日を求めるには FRIDAYという列挙型定数を使えばいいことが分かった。

あとはこれらを組み合わせてプログラムを書くだけである。

というわけで書いたのがこのプログラム。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.DayOfWeek;
import java.time.LocalDate;

import static java.time.temporal.TemporalAdjusters.lastInMonth;

public class LastFriday {

    private static final Logger logger = LoggerFactory.getLogger(LastFriday.class);

    public static void main(String... args) {

        var lastFriday = LocalDate.of(2017,2,24);
        logger.info(lastFriday.toString() + " " + lastFriday.getDayOfWeek());
        for(int i = 0; i < 99; i++) {
            lastFriday = lastFriday.plusMonths(1).with(lastInMonth(DayOfWeek.FRIDAY));
            logger.info(lastFriday.toString() + " " + lastFriday.getDayOfWeek());
        }

    }

}

まぁQiitaだと1年半ほど前に既に既出なんですけどね。

qiita.com

答えをすぐに検索するのではなく、JavaDocの中をどのようなキーワードで検索して書いたかの備忘録としてネットの片隅にメモしておく。

オリジナルのmaven archetype を作った

これは何?

デフォルトでmavenコマンドからJavaプロジェクトを作成すると、Java5+JUnit3.8.1のプロジェクトが出来る。 流石に古いので最新バージョンのプロジェクトが出来るようにオリジナルのarchetypeを作成したときのメモ。

作成手順

Maven – Guide to Creating Archetypes を見ながら手を動かせばそれなりのものが出来る。

作ったもの

github.com

メモ

  • JUnit5の依存関係はJUnit 5 User Guideチュートリアルにあるmavenプロジェクトの記述をコピーした。
  • ただ、サンプルプロジェクトの記述をコピーしただけだとeclipseでJUnit5を動かそうとすると落ちるので記述の追加が必要。

qiita.com

感想

意外に簡単だった。

"git configをプロジェクトによって使い分ける" 導入メモ

"git configをプロジェクトによって使い分ける" 導入メモ

Gitアカウントを使い分ける必要が生じたので qiita.com

を見ながら作業しようとしたら上手くいかなかったのであれこれ試行錯誤したときの個人的なメモ。

うまくいかなかったところ

gitconfigを見ながら書かれている通りに書いたつもりなのに、使い分けが出来ていなかった

原因

"Git v2.13.0(2017/05/10リリース)でgit configにConditional includes(条件付きインクルード)という機能が実装され" とあるのに、ローカルのGitのバージョンが2.9だった。

やったこと

sbtをインストールする · Scala研修テキストchocolatey.org

というツールがあるのを知った。 コマンドで一括更新できるという部分に魅力を感じていたので、まずは chocolatey をインストールする。

chocolatey のインストール

Installation に書かれているコマンドを実行すればいいが、PowerShellを管理者モードで起動しないとエラーになる、というところで一度はまる。 管理者モードで立ち上げた後はハマリポイントは無かった。

Gitのインストール

  • chocolatey.exe list -v -e Git でGitがバージョン管理下にあることを確認する。2.19が存在することを確認出来た。
  • chocolatey.exe install Git でGitをインストールする。
  • git --version で2.19がインストールされていることを確認する。

改めて git config を編集

Windowsなので\\でエスケープしないといけないのかなと思い、パスを\でエスケープしてみたが設定が反映されない。 検索したら stackoverflow.com を発見したので読んでみる。 回答の記述がスラッシュでの記述だったので、スラッシュに書き直してみる。 確認コマンドも回答に書かれているように、

git config --show-origin --get user.email

で確認してみた。

[includeIf "gitdir:C:/Users/<users>/Documents/sampledir/"]
  path = .gitconfig_work

と定義したとき、

sampledir  ← .gitconfig の定義が使われる
   ├ aaa  ← .gitconfig_work の定義が使われる
   └ bbb  ← .gitconfig_work の定義が使われる

ということが分かった。

コツコツとプレイする

モンスターストライクというゲームが好きで毎日コツコツ遊んでいる。

このゲームは、極論を言えばクエストをクリアしてゲットできるモンスターを99体集めて運極にするゲームなんである。

99体集めるためには、コツコツとプレイしないといけないし、クエストにピッタリとはまる手持ちのモンスターがいるかどうかも重要な要素なので、作りたくても作れない状況はある。

また、手持ちは充実していても、プレイヤーのスキルやクリアするための知識が足りていないとクリアできない。

なので、欲しいモンスターがいたら、ゲットするために色々と事前準備をしてから挑むんである。

まぁそれでも自分に合わないクエストは途中で放り投げてしまうんだが…

 

最近、ふっとシステム開発や既存のシステム修正も似てるなぁと思うようになった。

コツコツとプログラムを組んだりテーブル設計を繰り返していくことで一つのシステムが出来上がる、あるいは新機能を追加できる。

でも、そのために必要な事前準備を怠ると精神的に辛いだけでゴールは達成出来ない。

それでもゴールするにはコンティニューしたり(残業だったり休日出勤だったり)ガチャ引いて人手を増やしてどうにかコツコツと実績を積み上げるんだけど…

 

それでも自分に合わないなぁというとき、それは使っているフレームワークが肌に合わない、あるいは使いにくいときなのではなかろうか。

何とかして手を動かせば、いつかゴールは見えるんだけど、手が全く動かない、今はそんな心境に陥っている。

ゲームだったらこのクエストはちょっとやめて(結果としてずっとやらない)他のクエストをやろう、ということが出来るんだけどお仕事はそうもいかないのが辛いところだなぁ。