やる気がストロングZERO

やる気のストロングスタイル

システム運用アンチパターン読んで思ったことメモ

システム運用アンチパターン読んだ。

あまりゆっくり時間とれなくて結構時間かけて少しづつ読んだのでもう忘れてるところもあったり、ちょっとうまく読み取れなかったところもあったりして間違った理解あるかもだが、印象に残った部分だけ書いてみる。

何が目的なのかを見失わないようにする

いくつかエピソードがあったが「何が目的なのかを見失わないようにする」というものが共通してあった気がする。

アラート通知

例えば、アラート通知が頻発するような状態だと人は次第にそれを無視するようになる。
なんのためにアラート通知を出しているのかと言うともちろんアラートの発生原因である問題を確認・解決するためなので、アラート通知を発生させまくることによってそれを無視するようになってしまうのは本末転倒というわけである。

  • 少し待てば自然解決する可能性があるならアラート通知せず少し待たせるべき。
  • 障害が起こる未来を予想してアラート通知しない。

など、アラート通知を出すかどうかは思っている以上に慎重になるべき。

なお、アラート通知の判断材料となる「しきい値」はだいたいにおいて「率」を利用すると良い。 例えば、http_status: 500の件数が100件あったとして、全体のリクエスト数が200リクエストだったのと、1億リクエストだったのとでは印象や、おそらく事象も全く異なる。

ゲートキーパー

なにかシステム関連で事故や問題が発生したとき、再発防止としてチェック項目や責任者のレビュー体制が設けられる事が多い。 レビューがあるおかげで事前にミスがあぶり出せる可能性はあるが、逆に失われている物があることも認識しておくべき。
失われているのはデプロイの回数や開発工数である。

重いレビュー体制を置いて些細なバグを事前に洗い出せることと、開発速度を鈍化させ、リリースのタイミングを遅らせることを天秤にかけて、本当にそのレビューは必要なのかどうかを考えたほうがよい。

普段の業務で蜜に関わっていない少し上の責任者へのレビュー準備はコスト的にかなり大きいので(2人日くらい使う気がする。。)よほどのメリットが無いと釣り合わないよな、と個人的には思ってます。

文字コードの円記号問題を復習したのでメモ。

文字コードの円記号問題を復習したのでメモ。

円記号問題

参考)
円記号 - Wikipedia

ざっくり

例えばmacvscodeにて、文字コードをshift-jisに設定して[¥]を入力して保存したあと、一度閉じて再度Shift JIS指定で開くと[¥]で保存したはずなのに[\]が表示されている。

何故こんなことが起こるのかというと、shift-jisでは[¥]と[\]は同一の文字であるから。
文字を表すバイト列は[¥]も[\]も5cになる。

バイト列5cを[¥]として表示するか、[\]として表示するかはフォントやエディタによりけりという感じ。

つまり、shift-jisで[¥]と入力すると、5cというバイト列で保存され、次に読み込みされた際には[\]として表示されたという感じ。

shift-jisとUnicode間での変換を行う際の問題

shift-jisに対して、unicodeでは[¥]と[\]はバイト列が異なる。 utf-8において、[¥]は5cになり、[\]はc2a5になる。

unicodeとshift-jisで1:1で対応していない状況なので変換を行うと問題がおこる。

unicodeで[¥\]と入力した文字列をshift-jisに変換して、再度unicodeに戻すと[\\]になってしまう。

これは、shift-jisに変換した際、[¥]と[\]の区別がないので両方とも[\(5c)]に変換されて区別がなくなってしまう。 その後、再度utf-8に変換する際には[\]に変換され、結果[¥\]は[\\]になってしまう。

フォントによって(主にWindows環境)は[\]は[¥]と表示されている

ややこしいが、[\]は歴史上の問題で主にWindows環境では[¥]と表示されている場合が多い。 Windowsでこの記事を見たら意味わからないことになっていそう。。(ブラウザ用のフォントはいい感じになってたりするのかも?)

バイト列を確認したりいじったりする方法

上記のように[\]と[¥]で見た目がフォントによっては全く同じだったりするので、どちらが出力されているのかはバイト列で確認するのが確実。

以下のテキストのバイト列を確認するには、

\
¥

以下のようにコマンドを叩く。

od -tx1 sample.txt
0000000    5c  0a  c2  a5                                                
0000004

まず[\](5c)が出力されており、次にLF(0a)が出力されて改行され、次に[¥] (a5)が出力されていることがわかる。
バイナリエディタを使えば、直接文字コードを打って表示を確認することもできる。

参考図書(かなり面白かった)

Go echoでformのpost処理後のリダイレクトがうまく行かずにハマった

Go echoでformのpost処理後のリダイレクトがうまく行かずにハマったのでメモ

やりたかったこと

formデータをPOSTで受け取って処理したあと、一覧ページにリダイレクトしたかった。

func (w *WebApp) 登録処理(c echo.Context) error {
    // postパラメータを受け取って登録処理
        ...
    // TOP画面へリダイレクトさせる
    return c.Redirect(http.StatusCreated, "/")
}

起こったこと

リダイレクト先でstatus500でエラーになってしまった。
調べると、リダイレクト先にPOSTでリクエストしていて、そんなRootingは用意していないので(Getしか用意していないので)エラーになってた。

間違っていたこと

返却statuscodeをhttp.StatusFound(302)にすべきだった。

return c.Redirect(http.StatusFound, "/")

そういえばそうでした。
登録完了してデータが作成されたので感覚でなんとなくStatusCreatedにしてしまってた。

【Java】annotationの定義方法と使い方

参考)独習Java

定義

package com.example.annotation;

import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME) // どの時点まで情報を保持するか決める
@Target(ElementType.TYPE)           // このアノテーションを付ける対象を決める
public @interface ClassInfo {
    String value() default "";
    String version() default "";
    String description() default "";
}

使い方 リフレクションを使って情報を取り出す

@ClassInfo(version = "2.1", description = "アノテーションの動作テスト")
public class App
{
    public static void main( String[] args ) throws ClassNotFoundException
    {
        var clazz = Class.forName("com.example.annotation.App");
        var info = (ClassInfo) clazz.getAnnotation(ClassInfo.class);
        System.out.println("バージョン:" + (info.value().equals("") ? info.version() : info.value()));
        System.out.println("説明:" + info.description());
    }
}

【SpringBoot】autoconfigureについて

SpringBootで何かライブラリを使う時、pom.xmlのdependenciesに記載すればもうDIコンテナから使えるオブジェクトが取得できてしまう。
これは自動構成:autoconfigureというSpringBootの機能で手がかからず良いように思うのだが、ずっと何かモヤモヤしていてそのあたりがようやくスッキリしたのでメモ。

ライブラリをSpringBootで使うために必要な作業とは

SpringBootで使いたいライブラリは、別にSpringBootの為に作られたわけではない場合がおおい。 そうでないと、SpringBoot以外では使えなくなってしまう。

そういったライブラリを使う場合、通常はインスタンス化するなどの作業が必要になる。 このときに色々と設定を引数で渡したりする。

以下のような感じ。

HogeLib hogeLib = new HogeLib(色々設定引数); // ライブラリをインスタンス化する。
hogeLib.someFunction(); // 便利機能が利用できる。

このライブラリをSpringBootのお作法で使うには、このインスタンス化の作業をDIコンテナに任せることになる。 つまり、Beanとして登録しておくことになる。

具体的には以下のようなConfigureクラスを用意することになるはず。

@Configuration
public class HogeConfiguration {

        @Bean
        public HogeLib hogeLib() {
                return new HogeLib(色々設定引数)
        }
}

でも実際は何もしなくてもDIコンテナからこのHogeLibは取得できてしまう。なぜ。

autoconfigureはBean登録をやってくれていた

上記の疑問の答えはautoconfigureだった。
org.springframework.boot:spring-boot-autoconfigure

これは
org.springframework.boot:spring-boot-starter
の依存に含まれていて特に意識しなくても使っていることになる。

この中で上記したBeanの登録作業を実際にやってくれている。

autoconfigureの内部を見てみると、たくさんのライブラリ用のConfigureクラスとPropertiesクラスがあり、これらを使ってBeanにライブラリのインスタンスを登録する処理が書かれている。 つまり、よく使われる代表的なライブラリは事前に初期設定を用意してくれていたのだった。

逆にいうとそれ以外のライブラリはもちろん自分でConfigureクラスを書いてbeanに登録する記述を書かなければならない。

スッキリした。

個人的に、こういった自動でいろいろやってくれる類のものは便利なのだが、何を自動でやってくれているのかを理解できるまで非常に落ち着かない。 なぜかうまく行かない時に手の打ち様がないという状態にさらされているのが怖い。

【SpringBoot】application.propertyについて

SpringBootって一つの事を実現する手法がいくつかあったりして初見はなかなか混乱する気がする。 application.properties周りもそんな感じで長い間混乱していたが、少し頭が整理出来てきたのでメモしておく。

参考) Spring Boot コア機能 - リファレンスドキュメント

application.propertiesの目的

SpringBootに限らずApplicationには内部に埋め込みたくない値がある。
DBの接続情報とかがそれで、内部に埋め込まず外部に用意する設定ファイルに記述することで、同じアプリケーションを異なる環境で動かすことができるようになる。

application.propertiesもそれを実現する手段の一つである。

application.propertiesに記述した値をどのように受け取るか

例えば application.propertiesに

app.name=太郎

と書いてあり、これを読み込みたい場合、

beanの定義にて

@Component
public class Person() {
    @Value("${app.name}")
    prvate Sting name;
}

とあれば、このPersonがDIコンテナによってインスタンス化されるときに、nameには「太郎」が入ることになる。

このように、DI時にデータをバインドさせる方法の1つとしてapplication.propertiesがあり、 これ以外にも色々方法がある。

参照) Spring Boot コア機能 - リファレンスドキュメント

補足)
外部ファイルにこだわらないのであれば、@Configurationアノテーションを使ったConfigurationClassでbeanを設定することで値を設定できる。
SpringBootで使うライブラリの設定方法について調べていると、ある記事ではapplication.propertiesを使っていたり、ある記事はConfigurationClassを使っていたり、 またある記事はxmlファイルでbean定義を書いていたり(これはSpringBootではなくSpringFrameworkの書き方?)して自分は混乱していたのだった。

application.propertiesとapplication.yaml

application.propertiesではなく、application.yamlとしてyaml形式で記述していてもSpringBootは読み込んでくれる。

ファイル配置位置

以下の場所にあれば読み込まれる。 下に記載したものほど優先される

プロファイル毎のapplication.propertiesを用意する

本番環境、開発環境で読み込みたい値が異なるケースのためにプロファイルという仕組みがある。

例えば、環境変数 SPRING_PROFILES_ACTIVEにproductionという値が入った環境では、 application.propertiesがまず読み込まれ、それに上書きされる形でapplication-production.propertiesが読み込まれる。

※その他実行時プロファイルを指定する方法は以下のような物がある

参考) Springのプロファイル機能、そしてSpring Bootのapplication.properties - Qiita

JUnitテストクラスに @ActiveProfiles("プロファイル名") を付加する
複数指定時は配列指定 @ActiveProfiles({"profile1", "profile2"})

java コマンドに -Dspring.profiles.active=プロファイル名 を付加する
複数指定時はカンマ区切り -Dspring.profiles.active=profile1,profile2

環境変数 SPRING_PROFILES_ACTIVE にプロファイル名を指定する
複数指定時はカンマ区切り SPRING_PROFILES_ACTIVE=profile1,profile2

補足) プロファイルごとにインスタンス化するbeanの内容を変えるために、@profileでプロファイルを指定することができる。

Spring Bootでwebアプリケーションが動作する仕組みの概要を調査したのでメモ

spring bootの使い方を勉強しててざっくりの使い方は分かったが、印象としては黒魔術的というか「なぜこれでwebリクエストを受けられてレスポンスを返せるのか」が全くわからなかった。

全くわからなかった原因として、Spring Bootは構成としてかなり上部レイヤーに位置していて、その下にはSpring FrameworkJava Servletなどが存在しており、これらの知識が不足している事があった。

裏で何が行われているかをなんとなくでも知っておきたかったので調べた。
分かったことをメモとして記載する。
(想像で補完している部分もあるので間違いがあったら教えてほしいです。)

Spring Web MVC

Spring BootでWebアプリケーションを書く際、以下のようなコードをControllerに書く。

@Controller
public class HelloController {

    @GetMapping("/hello")
    public String handle(Model model) {
        model.addAttribute("message", "Hello World!");
        return "index";
    }
}

こう書けば、getで/helloでリクエストがあればこのhandle()メソッドが実行され、index.htmlのviewテンプレートでレスポンスが返される。
この機能はSpring Web MVCによって実現されている。

続きを読む