見出し画像

【PDO新卒】内定者インターンで学んだこと

こんにちは。パーソルプロセス&テクノロジー株式会社 PDO/24卒の山本です。

私は10月から、実際に参画するチームにインターンとして参加しており、そこで得たことを文字にしてみなさんにお届けしようと思います。


インターンを始めた経緯

もともと文系の学部出身ということもあり、他の情報系の学生と比べて知識やスキルが足りないと思っていたため、入社前に力をつけたいと考えていました。そのため、プログラミングを使ったインターンに参加したり、情報系の資格の取得に励んでいました。
そんな中で、実際の業務を体験してみないかとお誘いをいただき、弊社のインターンに参加する運びとなりました。
参加してみて、レベルの高いエンジニアの方がたくさんいましたし、自分の足りないスキルや経験が可視化できたのでとても有意義な時間でした。

UML図作成

最初に上司から与えられた課題は、セールス系のマネジメントツールとして会議、資料の抜け漏れを管理するTodoアプリのバックエンドAPI開発を行うことでした。
(バックエンドとは・・・アプリを使う人からは見えない内部の処理のことです!)
(APIとは・・・ユーザーから受け取ったリクエストを返すものです!)

そのために、まず上司にヒアリングをした後にユースケース図やモックアップ図などのUMLを使って欲しい機能や画面の構成について考えました。
(UMLとは・・・APIの機能や振る舞いを可視化するものです!)

こちらはメンバー用のユースケース図であり、Todoを追加したり、削除できるようにしました。
(ユースケース図とは・・・APIの機能ごとに分けた図です!)
大まかにはCRUD(Create,Read,Update,Delete)と呼ばれる、どんなシステムにも必要な機能を盛り込んでいます。

こちらはログイン画面のモックアップ図であり、一般的によく見るログイン画面のような感じにしました。
(モックアップ図とは・・・ユーザーから見える画面を図式化したものです!)

こちらはログインのシーケンス図であり、ユーザーやサーバのやり取りを可視化したものになっています。

こんな感じ。。。ですね。
こうした図を書くのにPlantUMLといったツールを使いました。
このツールを使うのもちょっとしたプログラムみたいなものを書くので個人的に楽しかったです。

API仕様書作成

次にAPI仕様書を作成しました。
これはサーバーに対してリクエストするパラメータを決めたりレスポンスのフォーマットを決めたりします。

API仕様書に関しては詳細は見せられないのでプログラムだけ見てみましょう。

こちらはユーザー作成APIのリクエストの例です。
ユーザーには最近ドジャースに移籍して話題の大谷翔平を使いました笑
ユーザー情報をサーバに投げるので、POSTメソッドを使いました。

curl -X POST -H "Content-Type: application/json" 
-H 'Authorization:Bearer "ログイン時に得られるアクセストークン"'
 -d '{
    "Email":"shohei.otani@test.co.jp",
    "Password":"otani3", 
    "Name":"大谷翔平",
    "IsAdmin":1
  }' 
  http://localhost:8080/allowed/user/new

こちらがレスポンスの例です。
パスワードはハッシュ化(暗号化して解読不能にする)したのち、データベースに保存します。そのため、レスポンスのパスワードは空にして返します。

{
  "email":"shohei.otani@test.co.jp",
  "password":"",
  "name":"大谷翔平",
  "isAdmin":1
}

こうした仕様書をAPIごとに書き、それに基づいてプログラムを実装していきます。

プログラムの実装

次にプログラミングの実装に入りました。
プログラミング言語はGoを使っており、フレームワークとしてechoを使いました。echoは他のフレームワークに比べて高速で、かつ柔軟にカスタマイズすることができます。

設計思想はClean Architectureを使いました。
この思想はビジネスロジックをフレームワークから独立することに一役買っており、プログラムの変更があった場合に柔軟に適応できる利点があります。
また、この思想を使うとそれぞれの層をまとめて管理できるのでテストがしやすいメリットがあります。
この思想を理解するのに時間はかかりましたが、実際に実装していく中で身につけることができました。

さらにDIを使って各レイヤーを独立したものにして行きます。
(DIとは・・・コードの各部分を他の部分から独立させるものです!)
それぞれの層にこんな感じの型を作って定義して行きます。
以下はinfra層のプログラムになります。

type TodoRepository struct {
	infra.SQLHandler
}

func NewTodoRepository(sqlHandler infra.SQLHandler) repository.TodoRepository {
	todoRepository := TodoRepository{sqlHandler}
	return &todoRepository
}

type TodoRepository interface {
	FindTodos(email string, pageint int) ([]model.Todo, error)
	CreateTodos(email string, t model.Todo) (model.Todo, error)
	DeleteTodos(email string, t model.Todo) error
	FindTodo(email string, number int) (model.Todo, error)
	UpdateTodos(email string, t model.Todo) error
}

最後にinjector層で各層を連結させてあげれば完成になります!
先ほどのrepositoryとDBの連結はこのようになります。

func InjectDB() infra.SQLHandler {
	sqlhandler := infra.NewSQLHandler()
	return *sqlhandler
}

func InjectTodoRepository() repository.TodoRepository {
	sqlHandler := InjectDB()
	return infra3.NewTodoRepository(sqlHandler)
}

テストコード作成

テストにはCircleCIという自動化ツールを使用しました。
GitHubと連動させることでpushした際に自動でテストを回してくれるので非常に便利ですね。

環境変数(テストする際の環境)は.envrcファイルに保存しておきます。
.envrcファイルを使うことでこのファイルが存在するレイヤーを読み込んだ時に自動的に設定してくれます。
これをローカル環境とCircleCIの環境のそれぞれに用意してあげて切り替えられるようにしてあげます。

以下がフォーマットの例になります。

#DBの環境変数
export ENV=
export DB_USER=
export DB_PASS=
export DB_HOST=
export DB_PORT=
export DB_NAME=
export DB_TABLE=

#JWTの署名
export JWT_SECRET=

次にテスト用の環境をmigrationを使って作って行きます。
(migrationとは・・・データベースを立ち上げる際のテーブル形式の移行方法のことです!)
これでCircleCIを立ち上げた時に自動でデータベースのテーブルが立ち上がるようになります。

CREATE TABLE IF NOT EXISTS todos(
    Email varchar(255) NOT NULL,
    Number int NOT NULL AUTO_INCREMENT PRIMARY KEY,
    Checked bool DEFAULT false,
    Content varchar(255) NOT NULL
) 

そして、このテーブルにテストデータを投入してあげます。
データには.ymlファイルを使いました。

-
  Email: "seiji.matumoto@ptest.co.jp"
  Number: 1
  Checked: true
  Content: "会議の予習"
-
  Email: "seiji.matumoto@test.co.jp"
  Number: 2
  Checked: false
  Content: "会食"

テストデータはfixtureを使って投入しました。
(fixtureとは・・・データをセットアップするときに必要な環境設定のツール)
testfixturesというパッケージを利用すればそこまで難しくなく実装することができます。

sqlHandler := infra.NewSQLHandler()
			err := testfixtures.LoadFixtureFiles(sqlHandler.Conn, &testfixtures.MySQLHelper{}, FixturesUserPath)
			if err != nil {
				log.Fatal(err)
			}

infra層にはこういった感じでテストコードを書いていったのですが、他の層にはmockを使いました。
(mockとは・・・何層にも重なったAPIをテストする際に、内側のプログラムが吐き出す値を固定するものです!)
mockを使うとデータベースに依存しなくて済むのでテストしやすいですね。

mockは使い方が難しかったので最初の頃は色々と調べまくりました笑

学んだこと

最初はわからない事が多く、その度に調べて自分なりの答えを出してそれを検証することが多かったです。
今となっては、新しいことを学ぶ際にそうした経験が生きていることを身に沁みて感じる場面が多いです。変化が多い時代に生きる私たちにとっては必須のスキルなのかもしれません。
これから新しいことを学ぶ人は諦めず貪欲に継続する姿勢があれば上手くいくと思います。
みなさんの挑戦に幸あれ。


いいなと思ったら応援しよう!