Goalist Developers Blog

PlayFramework2.6(Java)での全リクエスト/レスポンスのログ出力

こんにちは。
増田です。

以前PlayFrameworkで全リクエスト/レスポンスを取る必要に駆られたので、
その方法をあれこれ考えたり調べりした結果をここに記しておきます。

準備

何はともあれその準備から

プロジェクト作成

ターミナルで

> sbt new playframework/play-java-seed.g8

あと僕はEclipseで開発しているので、それ用の設定としてちょこっと。
project/plugins.sbtに1行追記

addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "5.2.4")

そして

> sbt eclipse

これでEclipseのための準備は整いました。

API作成

APIがないとリクエスト飛ばして試せないので仕方なく作ります。
routesに

GET     /api/get                    controllers.ApiController.get
GET     /api/getWithArg/:arg        controllers.ApiController.getWithArg(arg: String)
+nocsrf
POST    /api/post                   controllers.ApiController.post

GETリクエストに、POSTリクエスト。
で、Actionとして

public class ApiController extends Controller{

    public Result get() {
        Request req = request();
        String res = "This is a response from get.";
        return ok(Json.toJson(res));
    }

    public Result getWithParam(String param) {
        Request req = request();
        String res = "This is a response from get(String).";
            return ok(Json.toJson(res));
    }

    public Result post() {
        Request req = request();
        String res = "This is a response from get(String).";
        return ok(Json.toJson(res));
    }

}

を設定。
適当にsessionも入っていたりする設定です。

本題

そんな状況で、可能な限り完璧な状態の全リクエスト/レスポンスの内容をログに出力する、
というのがやりたいことです。
「完璧な」というのはリクエストメソッド、リクエストURL、リクエスト/レスポンスbody、セッション、など。

リクエストはcurl使うなりChromeの拡張使うなりフロント作りなりして適当に。
僕はChromeの拡張を使いました。便利!

気合いでLoggerを挟む

こんな感じです。

public Result get() {
    Request req = request();
    Logger.debug("Request(Controller) : " + req.toString());
    Logger.debug("Session(Controller) : " + session("SESSION"));

    String res = "This is a response from get().";
    Logger.debug("Response(Controller) : " + res + "\n");
    return ok(Json.toJson(res));
}

public Result getWithParam(String param) {
    Request req = request();
    Logger.debug("Request(Controller) : " + req.toString());
    Logger.debug("Session(Controller) : " + session("SESSION"));

    String res = "This is a response from get(String).";
    Logger.debug("Response(Controller) : " + res + "\n");
    return ok(Json.toJson(res));
}

public Result post() {
    Request req = request();
    Logger.debug("Request(Controller) : " + req.toString() + " ; " + req.body().asJson());
    Logger.debug("Session(Controller) : " + session("SESSION"));

    String res = "This is a response from post().";
    Logger.debug("Response(Controller) : " + res + "\n");
    return ok(Json.toJson(res));
}

すると、まぁ普通にログを取れて、

[debug] application - Request(Controller) : GET /api/get
[debug] application - Session(Controller) : session_content
[debug] application - Response(Controller) : This is a response from get().

[debug] application - Request(Controller) : GET /api/getWithArg/arguments
[debug] application - Session(Controller) : session_content
[debug] application - Response(Controller) : This is a response from get(arg).

[debug] application - Request(Controller) : POST /api/post ; {"body":"body_content"}
[debug] application - Session(Controller) : session_content
[debug] application - Response(Controller) : This is a response from post().

ただ、これは気合いでしかありません。

今回の例ではAPIが3つしかないから全然問題ありませんけど、
このAPIが10、20、30...と増えてきたら、それはもう大変面倒なことに...。
でも精々数十くらいなら書いてしまっても大丈夫といえば大丈夫な気がします。

ちなみに、sessionは

session("SESSION", "session_content");

みたいな感じで設定されているものとしています。

これはしんどいので、別の方法を考えます。

Filterを利用する

Filterが何かは僕もよく分からないので割愛します。
他の方々のありがたい記事がありますのでそちらを参考にしていただいて。
とりあえずリクエストやレスポンスをフィルターしているものなのだろうという理解です。
Filterを使ってリクエスト/レスポンスをログに出力してみます。
まず、app下にfiltersディレクトリを作って、その下にMyFilterクラスを適当に作ります。
こんな感じです。

public class MyFilter extends Filter{
@Inject
    public MyFilter(Materializer mat) {
        super(mat);
    }

    @Override
    public CompletionStage<Result> apply(
            Function<Http.RequestHeader, CompletionStage<Result>> nextFilter,
            Http.RequestHeader requestHeader) {
        long startTime = System.currentTimeMillis();
        return nextFilter.apply(requestHeader).thenApply(result -> {
            long endTime = System.currentTimeMillis();
            long requestTime = endTime - startTime;

            Logger.debug("Request(Filter) : " + requestHeader.method() + " " + requestHeader.uri());
            Logger.debug("Response(Filter) : " + result.body() + "\n");

            return result.withHeader("Request-Time", "" + requestTime);
        });
    }
}

あと、このフィルターを有効にするためにapplication.confに1行

play.filters.enabled += filters.MyFilter

を追記します。

すると、こんな感じに。

[debug] application - Request(Filter) : POST /api/post
[debug] application - Response(Filter) : play.http.HttpEntity$Strict@273ad9ad

面倒になったのでPOSTリクエストだけで試しました。
この方法だとリクエストボディもセッションもレスポンスボディの内容も取れないので、残念。
そもそも用途が明らかに違うのでそんなこと言っても仕方ないのですが。

ただ、これなら一々全てのAPIに何かを加えたりという気合いは必要ありません。

Authenticatorを利用する

Authenticatorが何かは僕もよく分からないので割愛します。
他の方々のありがたい記事がありますのでそちらを参考にしていただいて。こちらなど。
なんだかリクエストをインターセプトしているみたいなのでそれを利用しようという魂胆です。
適当にappの下にauthenticatorsというディレクトリを作って、その下にMyAuthenticatorというクラスを作りました。

public class MyAuthenticator extends Authenticator {

    @Override
    public String getUsername(Context ctx) {
        String session = ctx.session().get("SESSION");
        Logger.debug("Request(Authenticator) : " + ctx.request() + " ; " + ctx.request().body().asJson());
        Logger.debug("Session(Authenticator) : " + session);
        Logger.debug("Response(Authenticator) : " + ctx.response());
        if (session != null) {
            return "ok";
        } else {
            return null;
        }
    }

    @Override
    public Result onUnauthorized(Context ctx) {
        String session = ctx.session().get("SESSION");
        if (StringUtils.isEmpty(session)) {
            return unauthorized();
        } else {
            return forbidden();
        }
    }

}

というようなことを書いて、あとはcontrollersの各Actionにアノテーションを

@Authenticated(MyAuthenticator.class)

というように付与すれば、そのアノテーションをつけられたActionへのリクエストは、
設定したAuthenticatorを通るようになります。
名前の通り本来は認可のための機構でしょうけど、細かいことは気にしません。
Authenticatorを通るので、だったらそこでログ取れば良いのでは、という安易な考えです。
でも、これだとリクエストは取れるものの、レスポンスが取れません。
こんな感じです。

[debug] application - Request(Authenticator) : POST /api/post ; {"body":"body_content"}
[debug] application - Session(Authenticator) : session_content
[debug] application - Response(Authenticator) : play.mvc.Http$Response@52f8ea91

レスポンスボディ...。

ちなみに、このアノテーションはAction毎にではなくクラス単位で付けることができます。

ActionCreatorを利用する

ActionCreatorが(割愛
他の方々の(割愛
適当にappの下にinterceptorsというディレクトリを作って、その下にMyActionCreatorというクラスを作りました。

public class MyActionCreator implements play.http.ActionCreator {
    @Override
    public Action createAction(Http.Request request, Method actionMethod) {
        return new Action.Simple() {
            @Override
            public CompletionStage<Result> call(Http.Context ctx) {

                Logger.debug("Request(ActionCreator) : " + request.method() + " " + request.uri() + " ; " + request.body().asJson());
                Logger.debug("Session(ActionCreator) :"+ctx.session().get("SESSION"));

                CompletionStage<Result> stage = delegate.call(ctx);
                stage.thenAccept(result ->{
                    Logger.debug("Request(ActionCreator) : " + result.body());
                });
                return stage;
            }
        };
    }

}

そしてFilterと同じように、これを有効にするためにapplication.confに1行

play.http.actionCreator = interceptors.MyActionCreator

を追記します。

これで出力させるとこんな感じです。

[debug] application - Request(ActionCreator) : POST /api/post ; {"body":"body_content"}
[debug] application - Session(ActionCreator) :session_content
[debug] application - Request(ActionCreator) : play.http.HttpEntity$Strict@21b69a9

どうしてもレスポンスボディだけ取れませんでした。
残念。

まとめ

というわけで自分にはこれが限界でした。
とりあえずActionCreatorを使っておけばたくさん取れるという認識です。
そして切り替えが簡単。
ちゃんと取れる上に何かもっときれいな方法はあるのだろうか...。

ちなみに、以上のものを全て繋げるとこんな感じで出力されます。

[debug] application - Request(Authenticator) : POST /api/post ; {"body":"body_content"}
[debug] application - Session(Authenticator) : session_content
[debug] application - Response(Authenticator) : play.mvc.Http$Response@32532696
  
[debug] application - Request(ActionCreator) : POST /api/post ; {"body":"body_content"}
[debug] application - Session(ActionCreator) :session_content
[debug] application - Request(Controller) : POST /api/post ; {"body":"body_content"}
[debug] application - Session(Controller) : session_content
[debug] application - Response(Controller) : This is a response from post().
  
[debug] application - Request(ActionCreator) : play.http.HttpEntity$Strict@21b69a9
[debug] application - Request(Filter) : POST /api/post
[debug] application - Response(Filter) : play.http.HttpEntity$Strict@d1c58c

へぇ、そんな順番なんだぁ、というただそれだけです。
こちらからの報告は以上です。

Go言語の構文

こんにちは。
暇な時に、経験がないことを触ってみたいと思いましたから、Go言語の勉強を始めました。
まず、Go言語の構文について紹介させていただきます。

1. パッケージ

Goのプログラムは、パッケージで構成されます。
書いているパッケージに、括弧で他のパッケージのインポートをグループ化し、factoredインポートステートメント( factored import statement )と言うことはできます。

package main

import (
    "fmt"
    "math"
)

func main() {
    fmt.Println(math.Pi)
}

2. 関数

Go言語で、関数のキーワードはfuncです。
関数は、0個以上の引数を取ることができます。
型名は変数名の後ろに書かれます。
関数は複数の戻り値を返すことができます。

package main

import "fmt"

func addAndSub(x, y int) (int, int) {
    return x + y, y-x
}

func main() {
    fmt.Println(addAndSub(5, 10))
}

上記のプログラムの出力結果は 15 5です。

3. 変数

Go言語で、変数を宣言するためのキーワードはvarです。
関数の中では、 var 宣言の代わりに、短い:= の代入文を使えます。
なお、関数の外では、キーワードではじまる宣言(var, func, など)が必要で、 := での暗黙的な宣言は利用できません。

package main

import "fmt"
var i, j int = 1, 2
func main() {
    k := 3
    fmt.Println(i, j, k)
}

上記のプログラムの出力結果は 1 2 3です。

4. Forループ

Go言語で、for ステートメントの3つの部分を括る括弧 ( ) はありません。
初期化ステートメントと後処理ステートメントがない場合、他の言語(JavaやPHPなど)のwhile ステートメントとして使えます。

package main

import "fmt"

func main() {
 
    for i := 0; i < 10; i++ {
        fmt.Println(i)
    }
 
    check:= false
    for !check {
        fmt.Println("Hello World")
        check = true;
    }
}

5. Ifステートメント

Go言語で、if ステートメントは、先ほどの for ループと同様に、括弧 ( ) は不要で、中括弧 { } は必要です。

package main

import (
    "fmt"
)

func signOfNum(x int) string {
    if (x > 0) {
        return "positive"
    } else if (x < 0) {
        return "negative"
    } else {
        return "zero"
    }
}

func main() {
    fmt.Println(signOfNum(2))
}

6. Switchステートメント

Go言語で、switch は他の言語(JavaやPHPなど)の switch と似ていますが、下記に重要な2つの違いことはあります。

  • 選択された case だけを実行してそれに続く全ての case は実行されません。 他の言語(JavaやPHPなど)の case の最後に必要な break ステートメントが Go では自動的に提供されます。
  • switchcase は定数である必要はなく、 関係する値は整数である必要もありません。
package main

import (
    "fmt"
    "time"
)

func main() {
    fmt.Println("When's Saturday?")
    today := time.Now().Weekday()
    switch time.Saturday {
    case today + 0:
        fmt.Println("Today.")
    case today + 1:
        fmt.Println("Tomorrow.")
    case today + 2:
        fmt.Println("In two days.")
    default:
        fmt.Println("Too far away.")
    }
}

Go言語で、switch条件のないswitchは、switch true と書くことと同じです。

package main

import (
    "fmt"
    "time"
)

func main() {
    t := time.Now()
    switch {
    case t.Hour() < 12:
        fmt.Println("Good morning!")
    case t.Hour() < 17:
        fmt.Println("Good afternoon.")
    default:
        fmt.Println("Good evening.")
    }
}

7. Deferステートメント

Go言語で、defer へ渡した関数の引数は、すぐに評価されますが、その関数自体は呼び出し元の関数がreturnするまで実行されません。

defer へ渡した関数が複数ある場合、その呼び出しはスタックされます。 呼び出し元の関数がreturnするとき、 defer へ渡した関数は LIFO(last-in-first-out) の順番で実行されます。

package main

import "fmt"

func main() {
    count:=0;
    for i := 0; i < 3; i++ {
        count++;
        defer fmt.Println(count)   
    }
    fmt.Println("done")
    fmt.Println(count)
}

上記のプログラムの出力結果は:

done
3
3
2
1

参考書類

今回の記事でGoの構文について少し紹介しました。
詳しい情報は下記のリンクにご参考ください。

EC2とELBでかんたんhttps環境構築メモ

AWSでhttps通信できる開発環境をさくっとつくる

こちらのお手軽パターンです

https://recipe.kc-cloud.jp/archives/11067

ドメインはすでに購入済み前提
証明書はACM(AWS Certificate Manager)で取得します

  • Amazon Linux 2
  • nginx 1.15
  • ALB(Application Load Balancer)

手順

  1. EC2インスタンス作成
    1.1. インスタンス作成
    1.2. インスタンス初期設定
    1.3. nginx導入
  2. ロードバランサー作成
    2.1. ALB作成 2.2. 証明書の設定
  3. http→httpsリダイレクト設定
  4. Route53設定

詳しく

1. EC2インスタンス作成

1.1. インスタンス作成

いつもこちらのqiitaみてます😘

qiita.com

今はAmazonLinux1と2のAMIどちらも選べますけど
今後のことを考えて2を選んでおきます

https://qiita.com/michimani/items/146d1f986d78e06d510e

EC2インスタンスにかけてるセキュリティグループで、80番ポートをオープンしておく

ロードバランサーの設定で使うため
サブネットは違うアベイラビリティゾーンでもうひとつ切っとく、使わないけど

こんな状態にしていきます

f:id:y-iio:20180925134027p:plain

1.2. インスタンス初期設定

yum更新

sudo yum update

タイムゾーンの設定

sudo timedatectl set-timezone Asia/Tokyo

1.3. nginx導入

こちらを参考にしました

www.rem-system.com

コミュニティリポジトリ使わないといけないので
後々面倒なことになったりするのかしら

sudo vi /etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/mainline/centos/7/$basearch/
gpgcheck=0
enabled=1

インストールと自動起動設定

sudo yum install nginx
nginx -version
sudo systemctl start nginx
sudo systemctl enable nginx

IPでブラウザからアクセスしたら

f:id:y-iio:20180925132459p:plain

デフォルトページが表示されてればおっけ〜です

2. ロードバランサー作成

2.1. ALB作成

いつもの😘

qiita.com

httpsリスナーを追加します

f:id:y-iio:20180925132531p:plain

2.2. 証明書の設定

ドメインはすでに持っている前提
ACMから新しい証明書をリクエストして使います

f:id:y-iio:20180925132544p:plain

あとは手順1で作ったインスタンスをターゲットグループに登録してELB作成

EC2インスタンスにかけてるセキュリティグループで、ロードバランサーのセキュリティグループを許可

ロードバランサーのDNSでブラウザからアクセスできるようになりました〜

3. http→httpsリダイレクト設定

公式を参考に設定ファイルを書き換えて

ELB を使用して HTTP トラフィックを HTTPS にリダイレクトする

sudo nginx -t
sudo systemctl restart nginx

4. Route53設定

route53のAレコードにロードバランサーのDNSを登録

ELB ロードバランサーへのトラフィックのルーティング - Amazon Route 53

これだけ!

Gitがやばい(3/3)!

Gitがやばいの最終編です!前回はbranch, merge, fetch, pullについて書きました。普通のプロジェクトにはここまでは必ず使うでしょう。

実は、もう一つのよくみる現象があります。それは「マージコンフリクト」です。「コンフリクト」が入ってるために何か怖いものに聞こえますが、とてもよくあって、とても簡単に解決できるものです。

マージコンフリクトを再現する

一編から使ってるプロジェクトを使って、マージコンフリクトを見てみましょう。

下準備

ちょっとした準備しましょう。masterブランチでA.txtとB.txtというファイルを作成してコミットしましょう。

$ nano A.txt
$ nano B.txt
$ git add .
$ git commit -m "A.txtとB.txtを追加しました。"

私は上記のようにしましたが、コミットすればなんでもOKです。 こういうのが出ます。

(Create mode image)
 2 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 A.txt
 create mode 100644 B.txt

コンフリクトはどういう状況でおきるのか

さて、状況を想像しましょう。

このプロジェクトには、二人が参加しています。二人はそれぞれのタスクがあります。 AくんはプロジェクトでA.txtのファイルで、「Aがすごい」を書くのがタスクです。 BさんのタスクはA.txtに「B.txtをみて!」を書き、B.txtに「Bが一番すごい」を書くことです。

くだらない内容ですが、重要なのはAくんとBさんが両方A.txtを編集することになります。こういう状況ではマージコンフリクトが起きる可能性があります。

シミュレーション

やってみましょう。AくんとBさんのためにそれぞれのブランチを切りましょう。

git branch B-branch

でBのブランチが作成できます(すでに知ってましたね)。

git checkout -b A-branch

上記のコードは

git branch A-branch
git checkout A-branch

を一行で書くためのやり方です。

f:id:c-pattamada:20180918160640p:plain

はい、現在A-branchにあります。では、Aくんのタスクをしましょう。 A.txtの中で、「Aがすごい」と書いて、保存して、コミットしましょう。

f:id:c-pattamada:20180918160723p:plain

masterに移って、マージしましょう。

git checkout master
git merge A-branch

ここでは、mergeのあとで書くブランチ名が現在checkoutされたブランチにマージされます。

f:id:c-pattamada:20180918160757p:plain

git logでAくんのコミットがみれます。ここは無事マージできましたね。問題なし!

マージコンフリクトが登場

では、Bさんのタスクも完了しましょう。git checkout B-branch

ここに気づくべきことが、A.txtがまだ空っぽのままです。なぜかというと、BさんのブランチがAくんのコミットの前の状態に切られたからです。 実際のプロジェクトでは、二人が同時に仕事している想定ですと、この状況はすごくよくあるかと思います。 A.txtに「B.txtをみて!」を書き、 B.txtに「Bが一番すごい」を書き、コミットします。 そして、masterに移ってマージしましょう。

git checkout master
git merge B-branch

うまくいきましたか?!や、ダメでした。 AくんとBさんが同じファイル(A.txt)を編集しましたので、gitが上書きすればいいのか、両方入れた方がいいのかなどがわかりません。 マージコンフリクトが行ってしまいました。

f:id:c-pattamada:20180918160825p:plain

マージコンフリクトを解決する

マージコンフリクトが起こっています。文字エディターでA.txtを開いてみますと驚くかもしれませんが…

<<<<<<< HEAD
Aがすごい
=======
B.txtをみて!
>>>>>>> B-branch

が書かれてます。javaだった場合には必ずコンパイルエラーが出るでしょう。

現在はmasterのブランチにB-branchをマージしようとしてますので、masterの現在のコミットはHEADと書かれてます。 <<<<HEAD=======の間には現在のmasterの状態。 =======>>>>>>> B-branchの間にはB-branchの状態。

今回は私が管理者で決める立場にあるので、両方の変更を含めたいと思います。 中身を編集して

「 Aがすごい
B.txtをみて!」

の状態で保存、または古い方を削除する判断もありえます。

ターミナルに戻り、git statusで様子みましょう。 マージしても大丈夫のファイル、B.txtが緑で、A.txtがまだaddされてないので

git add A.txt
git commit -m "マージコンフリクト解決"

おめでとう!初コンフリクトを解決できましたね。

最後に

ここでは、マージコンフリクトがどういう状況で起きるのか、そしてどんな風に解決できるのかについて書いてみました。この記事の内容と以前投稿した二つの記事で通常の時のgitは使えるかと思います。

Gitの機能は他にも山々あります。特にrebase, cherry-pick, submoduleなどが面白いですが、興味があるかたはそちらも調べてみてください(またあとで、私が投稿する可能性もありますw)。

これでGitに対しの自信が持てるようになってたら嬉しいです!

ちょっとした復習に、

Gitを使う利点

1) バージョニング管理で定期的にサーブ・ロールバックができる。

2) 複数の人が同時に複数の関係ない機能を同時に開発できるシステム

だと思いますので、一人のプロジェクトでも、大きいなプロジェクトでもとても便利です!

ぜひ、使ってみてください!

Getting Started with Dart (1/∞)

(Once again the lines above are editable so go ahead and replace my name with yours and press play button ▶️)

If you have missed my previous blog, you may find it here

developers.goalist.co.jp


Let's start learning the fundamentals of Dart.

f:id:vivek081166:20180827200359p:plain

In this tutorial, we shall learn about the basics of Dart Programming Language.

DartPad

Having the Right Tool for the Right Job is Important. Isn't it?

DartPad (https://dartpad.dartlang.org/) is an open-source tool that lets you play with the Dart language in any modern browser.

Yeah!! you read it correctly... No Installation... No Environment Setup...
DartPad is all you need to start learning/coding in Dart. Just open a DartPad on your browser and start writing your dart program.

f:id:vivek081166:20180827162548p:plain

On the left, you have workspace to write program and after clicking ▶️ Run button output of the program will be displayed in the console on right.

Dart Fundamentals

Program Structure

All Dart programs have to start with main()
main() is what we call a function and a function basically is a part of the program that does something. (more on that in subsequent bog :D stay tuned)

f:id:vivek081166:20180827164801p:plain

In the above code, program flow stars with void main()thereafter program prints Hello on console with print function print("Hello")
All dart programs have to start with main()

Variables and Typing

As you know, in programming, variables are used to store information to be referenced and used by programs. In other words, a variable is a value that can change, depending on conditions or on information passed to the program.

There are two ways to declare a variable in Dart
1) Dynamic Typing
2) Static Typing

Dynamic Typing

Dynamic typing is a weak typing which you might have seen in Javascript where a variable can have different types based on the type of value assigned to it.
Dynamic Typing : Variables can have different type
Let's try declaring and initializing variables with Dynamic Typing



In case of weak typing; type of a variable change depending on the circumstances.
In the above program, variable var a can hold a value of any type (string, integer, boolean etc.)
When not initialized all variables declared with var identifier always hold null value.


Side Note:

Single Line Comment in Dart Start with "//"
e.g.
// This is a single line comment

Multi Line Comment in Dart is enclosed in "/**/"
e.g.
/*
* This is supposed to be
* a multi-line comment.
*/


Static Typing

Static typing is a strong typing which is similar to other programming languages like Java, C more recently Typescript, where type is stated while declaring the variable and cannot be changed later.
Static Typing : Type of the variable is stated while declaring it and cannot be changed.


Life is easy with Strict Type checking, isn't it?

f:id:vivek081166:20180827183926p:plain


Learn about Dart in details here

www.dartlang.org

じゃ、That's it for this post... will come back with more on this...
Till then happy learning... :)

新卒三期、ブログを書く(エンジニア編)

こんにちは。

今年新卒として入社し、開発部に配属となった増田です。

以前、マスダさんという方がデザインブログに自己紹介を書いていますが、別人です。
僕はスプラトゥーンやっていません。
ただ、そのマスダさんとは出身大学も年齢も勤務地も同じだったりします。
どうでも良いです。

さて、ここから自己紹介(という名目の自分語り)をだらだらと。
技術ブログではありますが、技術的なお話は何もありません。


入社前

僕はゴーリストに入社する以前は精神的に健康的な大学生活を送っていました。
いや別に今精神的に不健康な生活を送っているというわけではないです。

どんな生活だったかというと、
お昼をすぎた頃に目を覚まし、お天気と気分が上々であれば服を着替え、
自転車に乗り、電車に乗り、大学へと向かい、
着いた後は大学の中にある一番大きな図書館の二階の、
これまた大きな窓に面する席で、
のんびりとただ読みたい本を読むなどする生活です。

その窓から見える細く高い木の枝や葉が、ゆさゆさ風に揺られているところとか、
自転車に乗っていたり雨の日には傘をさしていたりする学生たちが
構内をぞろぞろと行き交っている様子とかを、
ときたまぼんやり眺めるような、そんなゆったりとした時間の中を生きていました。

講義は必要最低限行かなければならないものにだけ行っていました。
なんなら必要最低限の講義さえ行かないことも。
おかげで一回生前期の取得単位数が一桁だったりしました。
そんな生活をした結果、二留。
ただの阿呆です。

あと大学にいたときには大学生らしくサークルに入っていて、
そのサークルの人たちと関わっているときにはしみじみと幸せに包まれたりなど。

あの時間が僕の人生のハイライトです。
どうあがいてもあれ以上幸せな時間はもうないだろうと思っています。
読みたい本を読み、好きな人たちと関わり、寝たいだけ寝て、...。

自然体。


就活

そんなのんびりした僕も、働かないといけません。
非常に残念ではありますが、現状そういうことになっているらしいので。

というわけで普通にイメージされるような就活をするのですが、
上手くいきませんでした。
上手くいかなかったというよりは面倒くさくなって諦めたと言うのが正しいのでしょうけど。
三社ほどにESを提出して、面接してもらって、それで終わりです。
諦めの早い、つまり潔い男なのです、僕は。

大きな挫折経験やそこから立ち直るまでの過程も、
何かを成功させたとか他の人を引っ張ったというような経験も、
人に話せるような立派な夢も目標も、
何もありませんでした。今もないです。

その上、志望動機は生活するのにお金が必要だからとりあえず働きたいというだけで、
その浅はかな動機を飾り立てるような元気もなく。
いろいろと無理でしたね。

でもむしろ僕みたいな人の方が絶対に多いはずで、
その辺の大学生が人に話せるような目立った経験とか立派な目標とか持ってるわけなくね
って思っています。持っていたらすみません。僕が世間を知らなかったということで。

基本的に親に言われるがままに受験したとか、
とりあえず公立の中高行って通りそうな大学に行って
普通にバイトしたりサークル活動したりしてたとか、
そういうものじゃないのですかね。知りませんけど。
とか言うのを書き続けると長くなるのでこの辺にして。


とはいえ働きたい(働かなければいけない)気持ちはあったので、
電子の海原を彷徨っていたときに見つけた採用イベントに参加し、
そこでたまたまゴーリストを知って、
流れのままに面接などをしてもらったら内定をもらえて、
というわけで僕はここでこうしてブログを書くに至っております。

ちなみに、いまだにどうして自分が内定をもらえたのかよく分かっていません。
こんな人間なので。
以前あった会社での食事会の際に、採用担当をされている人事の方から
「いや本当なんで採用したんだろうね」というようなことを言われもしましたし、
僕が採用されたのはたぶん何かの間違いなのでしょう。

でもまぁ何かの間違いだったとしても
幸運なことに今更採用面接がやり直されたりすることはないのです。
むしろこの僕をどう上手く使うかは上の人の腕の見せ所、
というくらいの気概でいます(嘘です。そんな大きな肝はありません)。


入社後

何はともあれめでたくゴーリストに入社して
東京の方で二ヶ月ほど研修を受けたのち、
どこかの部なりチームなりに配属されて、僕は大阪に移り、
そこから職種別研修があり、というような流れがあるのですが、
そういうのは他の新卒さんのブログを読んでいただければ分かると思いますので
僕は省いていきます。
そう、ビジネスでは効率の良さが求められるらしいのです。
ちなみに、僕の研修の成果はこちらに。

研修という名前はしていますが、順を追ってあれこれ教えてもらうようなものではなく、
初めはがっつり放置されてどうしようもなくなった頃に解答を提示される、
というような感じでした。僕の場合は。
僕以降の人(2019以降の大阪の新卒エンジニア?)は放置されるようなことはたぶんないらしいです。

一応大学の頃にちょこっとプログラミングに触れたりはしていたものの、
そんながっつりやったことはなく、
なのに全然知らない言語とかフレームワーク(この言葉自体理解していなかった)とかを言われて、
じゃ後は頑張ってね、なんて。
いや厳しいものでした。

今はその研修のときとはまた別のプロジェクトに割り振られ、
毎日パソコンの画面を見ながらプログラミングをしております。
プログラミングしかしておりません。
目が疲れます。
あとお腹もよく痛めます(汗と冷房のせい)。


大阪支社

せっかくなので僕のいる大阪支社の雰囲気をちょっとだけお伝えしようかと思います。

とにかく東京の本社の方に比べて静かです。
ざっくり言うと会話がないということなのですが、
でも最近は比較的賑やかな場面もあったりして、
別に非人間的な生活が営まれているというようなわけではありません。

人数が今のところ5人で、僕にはすごく心地良いです。
でもきっと今後増えていくのだろうなぁという予感はあります。予感というか、増えていきます。

僕は周りの人が増えれば増えるほどその人たちとの間に距離を感じてしまうらしいので、
人が少ないのはすごくありがたいです。少なすぎるとあれですけど。

大阪支社の上司(という言葉は正直違和感しかないのですが)の方々(と言ってもお二人)も、
先輩も同期もみな良い人たちで、感動しております。
僕自身が良い人かどうかは知りません。人によりけり。


そんな感じでもう十分書いた気になったので、この辺で。
結局大阪支社は静かなところということしか書いていませんが、
それで全部と言っても過言ではないでしょう(流石に過言)。


おしまい(終わりはいつも突然に)。


Visual Studio Code拡張機能の紹介

こんにちは。

Visual Studio Codeはマイクロソフトによって開発されているソースコードエディタです。

Visual Studio Codeの利点は無料で、使いやすいことと多くのプログラミング言語に対応していることです。 また、適切な拡張機能をインストールすることで、標準では用意されていない機能を追加し、Visual Studio Codeをさらに便利な開発環境に進化させることができます。

現在、ゴーリストのフロントエンドチームはAngularを使っているので、本日Angularを使うフロントエンド開発のため、いくつかの好きな拡張機能について紹介させていただきます。

1. Angular 6 Snippets

Angularをプログラミングするとき、AngularのキーワードとAngularの構文とAngularのコーディング規約を補完するための拡張機能です。Angularプログラマに非常にお勧めです。

Angular 6 Snippets - TypeScript, Html, Angular Material, ngRx, RxJS & Flex Layout - Visual Studio Marketplace

2. CSS Grid Snippets

2次元レイアウトを、HTML/CSS を使って簡単・自由に操作できるCSS Gridの構文を補完するための拡張機能です。フロントエンド開発者とデザイナーに非常にお勧めです。

CSS Grid Snippets - Visual Studio Marketplace

3. Debugger for Chrome

Google Chromeを使って、Visual Studio Codeソースコードエディタでソースコードに直接的にブレークポイントを追加して、デバッグするための拡張機能です。フロントエンド開発者に非常にお勧めです。

Debugger for Chrome - Visual Studio Marketplace

4. TSLint

書いているTypeScriptのソースコードを解析して、既に定義されたルールに違反していることがある場合、警告が出される拡張機能です。プログラムの保守性・安全性を保ち、機能的なバグを防ぐため、TypeScriptプログラマに非常にお勧めです。

TSLint - Visual Studio Marketplace

まとめ

良いツールを使うことで、プログラミングは大変なことから楽なことになりますね。

Visual Studio Code拡張機能をインストールすることは簡単です。上記の各リンクをクリックして、拡張機能の表示ページにある「Install」ボタンをクリックすれば、拡張機能は自動的にインストールされます。
デフォルトではなくて、拡張機能を詳しく設定したい場合、上記の各リンクをご参考ください!

紹介させていただいた拡張機能を使ってみて、楽しいプログラミングの時間をお過ごしください!