ソムリエでエンジニアのブログ

ワインの事も書きたいけど基本エンジニア用

2021年を振り返る

はじめに

2019年8月にwebエンジニアとしてのキャリアをスタートし早2年半。
初めてのwebエンジニア→webエンジニア転職も を経験し、成長を感じれる部分もありました。
今年も残すところ数日となったのでそんな2021年をざっと振り返っていこうと思います。

最初に2020年の目標を振り返る

  • 自身の得意分野・興味分野を見つける
  • エンジニアとして人脈を広げる
  • 減量を成功させる

エンジニア

[1月]
TypeScript、Angularを使った開発現場にアサイン。
フロントエンドをがっつり触るのはこの案件が初めてでしたが稼働は安定していたので、業務後や週末の時間を使いながら技術のキャッチアップ を行なったのを覚えています。
2020年の11月頃から転職を考えていましたが、比較的モダンな技術を触れるという事で一旦保留にしました。

[2月]
ほぼ定時上がりの毎日でした。
所属企業の受託チームから気づいたらSESチームに名前が移動しているという珍事もありました(笑)
渡された画面仕様に沿ってレビューされる事もなく我流で実装していく毎日に、このまま続けても作業者として経験年次が増えていくだけではないかと不安が込み上げてきました。
ここで転職を決意し、本格的に転職活動をスタートさせました。

[3月]
カジュアル面談、面接を受ける日々でした。
会社選びに関しては、上流に関わりたかった、ユーザーからのフィードバックを受けたかった事から自社開発企業を中心に面談を設定。
この時期には所属企業とのやりとりほとんどなかった気がする(笑)

[4月]
転職活動の結果2社から内定をいただきました。

① 自社開発企業 Laravel/Ruby on Rails/Angular 東京 フルリモート
② 自社開発企業 Laravel/Vue.js 大阪 リモート可

ドメイン領域、給与的には東京の企業に興味がありました。ただ組織規模が少々大きかった事、フルリモートという働き方が個人的に今のレベル感で不安だった事から大阪の企業を選択しました。

[5月]
転職に向けてDDD、各種アーキテクチャをインプットメインで学習していました。
5月末にSES企業を退職。向上心の強い実務未経験メンバーと共にキャリアを過ごせた事は自分にとって大きく、前職には感謝しています。


[6月 - 8月]
現職に入社。
研修として社内で利用するサーバー管理アプリを要件定義〜リリースまで対応する事に。
3ヶ月も研修期間もらっていいんかって思ってました(笑)

入社前にDDDやアーキテクチャに関してのインプットを行なっていたものの、ゼロベースで実装するとなるとどうしていいやら。
書籍を調べながら強強エンジニアに相談しつつ実装を進めました。
この研修だけでも転職した意味があったのではないかと感じるくらいの成長を感じる事ができました。具体的には、

・DDDのモデリング手法を実際に体験できた。
・レイヤー化する意図、メリットが実際に肌感として感じる事ができた。
・自動テストをシステム全体に取り入れ、その恩恵を感じる事ができた。
・リファクタリングを通して依存度の高いコードが起こす問題を実感できた。

上記以外にも多くの収穫がありました。
巷ではよく言われてる事ですが、この研修通して手を動かして学ぶ大切さを実感する事ができました。


[9月]
DDDにさらに興味をもち関連書籍に色々と手をだしました。ただエヴァンス本に関してはなぜか手を出さず、、、

前職の同僚からの誘いで同じくらいの経験年次の方との設計談義に参加しました。
普段人と関わる事が少ない引きこもりですが、今年の目標が「エンジニアとして人脈を広げる」だった事を突如思い出し参加。
やはり同じような箇所で悩んでいる事もあれば、経験してきた事によってそれぞれ強みが違ったり。
こういった会には今後も積極的に参加していきたいですね!


[10月]
新規開発のチームにアサイン。 研修の経験を活かし、モデリング、自動テストの導入やオニオンアーキテクチャを採用し実装を進めています。
チーム内にDDDに精通した開発者がいないので、モデリング手法の共有や、技術選定・アーキテクチャ・DB設計、コードレビューも担当しています。

技術選定では、Vue3系を採用したかったのですが、Vuetifyが3系に対応していないという事でVue2系×Composition APIを採用しました。

入社時点では自分がこのようなポジションになっている事を想像もしていませんでした。

[11月]
新入社員の研修メンターをする事に。
経験できた事は非常に良かったですが、自身の実力不足を感じる場面も多かったです。(特にインフラ関連...)
技術だけでなくビジネスパーソン的にも成長する必要を感じています。
課題も感じた一方で円滑にプロジェクトを進める為の開発フローなど新たな興味分野もできました。


[12月]
引き続き新規チームでのレビュー、実装に加えて、研修のメンターを継続。
個人ではモデル駆動開発の勉強会に複数回参加し、モデル駆動開発にさらに興味を持つ事となりました。

自宅の作業椅子にエルゴヒューマンプロを導入。体の負担がかなり軽くなりました。

筋トレ

4月から9月まで減量を実施。78kg→65kg(13kg)落としました。
今回の目標は、脂肪を落とし切る事だったので仕上がり体重はかなり軽めに。70kgで仕上がるような筋肉量を手に入れたい、、、
体重の減少幅は過去1でしたが、白米ベースで減量をした事もあってかしんどさは一番なかったかも。

2021年総括

それまで渡されたタスクをただ進める事ばかりでしたが、転職後は自身で考え進めていくような仕事が増え、エンジニアの仕事がより一層楽しく感じるようになりました。
1年ちょっとの経験で転職する事を少々悩みましたが、振り返るとその決断をしてよかったな思います。

2022年の目標

・モデル駆動開発の経験をさらに積む
・サーバー周りの実務経験を積む
・チームビルディングに携わる
・LTの経験をする
・文章力向上の為、ブログ(Qiitaなど含む)を月1本更新
・ベンチプレス100kgを達成する

アジャイルについて知らない事だらけだったので『アジャイルサムライ』を読んでみた

はじめに

アジャイルってなんか短いスパンで開発するんでしょ?」

以前の私はアジャイル開発に対してこの程度の認識で、その内容をはっきりとは捉えていませんでした。
自社でも開発フローを見直したいというニーズがありこの機会にアジャイル開発を詳しく知りたいと考え『アジャイルサムライ ~達人開発者への道』を読んでみたので印象に残った内容と感想をまとめておきます。

顧客が積極的チームに関わる

書籍では、顧客が積極的に関わらない開発を「犯罪的」と嘆いています。
プロジェクトは顧客の課題を解決するものであって、その当事者の意見を継続的に取り入れられない開発が顧客のイメージから徐々ズレていく事は容易に想像できます。

プロダクト開始時に失敗が決まる

驚く事にスタートを切る前からだめになってしまうプロジェクトが世の中に多くあるようです。
その原因は、プロジェクト開始時点で思い描く成功が各々異なっている事です。この状態で開発を進めていくとシステムは完成したがニーズと合わないものになる悲惨な結末を迎える事になります。
このような状態に陥らない為、チーム内でゴール、ビジョンを共有する事が重要になります。

インセプションデッキを使うメリットを考察する

インセプションデッキでは10個の設問が用意されています。
その中でプロジェクトの全体像を捉えるものと、プロジェクトの具体的な解決策を検討する2つのフェーズに分類されます。
特にメリットを感じたのは前者で、作ろうとしているものの背後にある「なぜ」をメンバー全員が掴む事でチーム、個人の振る舞いが変わってくると思います。
誰が何をする為のシステムかを理解する事で、やる事・やらない事、優先度、画面の見せ方など的確な判断が下せるようになります。
インセプションデッキの個々の設問についてはこちらにわかりやすくまとめていただいているので参照ください。
crowd.itpropartners.com

既に動いているプロジェクトでもインセプションデッキを作るべきか

既に稼働しているプロジェクトにアジャイルを取り入れる際、インセプションデッキを作るかどうかの判断は、問題がチームの方向性にまつわる事で、チームの全員が以下の5つの質問に答えられるかが基準になります。

  • このプロジェクトにいるのはなぜか?
  • 成し遂げようとしている事は何?
  • 顧客は誰?
  • 解決すべき主要な課題は何?
  • 最終判断を下すのは誰?

プロジェクトのゴール、ビジョンの共有ができているか、チームに巻き込むべき顧客を認識できているか、決定権の所在を認識できているかをはっきりさせる為の質問に答えられる状態であれば、スタート地点には立てています。。

最後に

プロジェクトの運用フローを見直す為のノウハウを知りたいという目的で読み出した書籍でしたが、プロジェクト方向づけが一番印象に残りました。
チームで品質に責任を持ち、顧客のフィードバックを受けながら改善していく流れは開発者としてもやりがいを感じれるフローではないかと感じます。
9章以降でプロジェクト運営に関する事がかかれているので再度時間を見つけて読みたいと思います。

iframeを使ってアプリケーション内に外部サイトを表示する

はじめに

フロントエンド開発で、あるページに外部サイトを表示したいとの要望がありiframe(インラインフレーム)を利用して対応を行ったのでその内容を記録しておきます。

iframe(インラインフレーム)とは...

iframeとは、HTMLタグの中にさらに別のファイルを埋め込むことができる要素を指します。
src属性で指定したURL(リンク先ページの内容)をインラインフレーム表示できるHTMLタグの一つです。 html4の頃は非推奨だったようですが、HTML5では非推奨が解除されているようです。

実装内容

localhost:4200でアクセスしたページ内にAngularドキュメントページを表示させていきたいと思います。 該当のhtmlファイルを以下のように編集します。

// Angularを利用してヘッダー部分を表示する為に利用しています。
<app-service-header
  [serviceName]="serviceName"
  [serviceCategory]="serviceCategory"
  (onClickedClear)="backToTop()"
>
</app-service-header>

// ※外部サイト表示箇所
<div class="iframe-container">
  <iframe
    src="https://angular.jp/"
    frameborder="0"
  ></iframe>
</div>
css

// ヘッダーの高さを定義しているファイル
@import "../../assets/styles/const.scss";

.iframe-container {
  height: calc(100% - #{$service-header-height});
  iframe {
    width: 100%;
    height: 100%;
  }
}

スクリーンショット 2021-03-04 13.46.51.png

上記のようにする事で、localhost:4200でアクセスしたページ内にAngularドキュメントページを表示させる事に成功しました。

おまけ

iframeのborderやスクロールバーを削除するには、scrolling="no"、frameborder="no"を利用します。scrilling="no"をすると画面が固定になります。

php artisan make:modelコマンドのファイル生成先を変更する

はじめに

最近、Laravelで開発しているプロジェクトにオニオンアーキテクチャを意識したディレクトリ構成を採用しました。
導入したディレクトリ構成ではモデルファイルをInfrastrucure/Eloquent/ディレクトリ 以下に置くよう変更を加えたいと思っています。

ここで一つ問題が、、、Laravel8系のデフォルトでは、モデルファイルがModelsディレクトリ 以下に位置しており、php artisan make:models ファイル名のコマンドを利用するとModels/ファイル名という階層でモデルファイルが作成されてしまいます。
採用したディレクトリ 構成に合うようphp artisan makeコマンドの生成先を変更したいと思い実現方法を知れべたのでこちらにまとめておきます。
※オニオンアーキテクチャに関しては今回の本題でない為説明を省きます。

環境

現状の処理を調査する

まずphp artisan make:modelコマンドの生成先がどこで定義されているかを調べていきます。
生成先が定義されているのは、vendor/laravel/framework/src/Illuminate/Foundation/Console/ModelMakeCommand.phpファイルにあるgetDefaultNamespaceです。

<?php
class ModelMakeCommand extends GeneratorCommand
{
   .......

    /**
     * Get the default namespace for the class.
     *
     * @param  string  $rootNamespace
     * @return string
     */
    protected function getDefaultNamespace($rootNamespace)
    {
        return is_dir(app_path('Models')) ? $rootNamespace.'\\Models' : $rootNamespace;
    }

    .......
}

上記の通りphp artisan make:modelコマンドはModelsディレクトリが存在する場合、Models以下にファイルを作成するようになっています。
Modelsディレクトリ を削除、毎回php artisan make:model Infrastructure/Eloquent ~と入力しても希望の形にはなりますがタイプが面倒です。 そこでこのメソッドを改良していきます。
ただしvendor以下を直接変更するのではなくオーバーライドしていきます。
※vendor以下を編集しない理由については以下記事にまとめられていたのでご参照ください。

biz.addisteria.com

実装

コマンドファイルの作成

まずは新規コマンドファイルを作ります。
以下のコマンドを入力するとapp/Console/Commands/ModelMakeCommand.phpが作成されます。

$ php artisan make:command ModelMakeCommand

メソッドをオーバーライド

作成されたファイル内でメソッドをオーバーライドします。

<?php

namespace App\Console\Commands;

use Illuminate\Foundation\Console\ModelMakeCommand as ConsoleModelMakeCommand;

class ModelMakeCommand extends ConsoleModelMakeCommand // ←元のコマンド定義を継承
{
    /**
     * Get the default namespace for the class.
     *
     * @param string $rootNamespace
     * @return string
     */
    protected function getDefaultNamespace($rootNamespace)
    {
        return $rootNamespace . '\\Infrastructure\\Eloquent';
    }
}

クラスをConsole/Kernelに登録

app/Console/Kernel.phpに作成したModelMakeCommandを登録します。

<?php

namespace App\Console;

use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;

class Kernel extends ConsoleKernel
{
    /**
     * The Artisan commands provided by your application.
     *
     * @var array
     */
    protected $commands = [
        'App\Console\Commands\ModelMakeCommand' // 作成したコマンドを追加
    ];

......
}

上記の手順でphp artisan make:modelのファイル生成先を変更する事ができました。
同様にコントローラーの作成先などを変更する事も可能です。

注意点

Laravel8系ではモデルファイルを移動させるとFactoryのファイルを見つけられなくなりエラーになります。
こちらの解決については後日別記事でまとめたいと思います。

.gitignoreを後から追加する方法

はじめに

TypeScriptを学んでいる時に、誤ってリモートリポジトリにnode_modulesディレクトリ以下のファイルを追加してしまいました。
そこでgit管理したくないファイルをコミットした際、後からgitignoreファイルを追加する方法を調べたので備忘録として残しておきます。

手順

1. 何はともあれ.gitignoreファイルを作成する

$ touch .gitignore

コマンドでもGUIでも構わないので、git管理を外したいディレクトリ・ファイルと同じ階層に.gitignoreファイルを作成します。

2. .gitignoreファイルに管理対象外にしたいディレクトリ・ファイルを記述
今回はnode_modulesディレクトリ以下を管理対象外に指定します。

node_modules/

.gitignoreファイルの記述方法についてはドキュメントや別記事を参照してください。

git-scm.com
3.ひとまずコミットする

$ git add .
$ git commit -m ".gitignoreの追加"


4.削除したいフォルダ・ファイルをリポジトリから削除する .gitignoreを設定しても、既にリポジトリに登録されているものはリポジトリに残ったままになっています。
そこで、下記コマンドを実行し、管理対象から除外します。

$ git rm --cached -r node_modules


5.管理対象から除外しコミットする 指定したファイル・フォルダをgit管理対象から除外することができるので、あとはコミットまでして完了です。

$ git add .
$ git commit -m "node_modulesディレクトリをgit管理対象外に変更"


これで誤ってリモートリポジトリにあげてしまったディレクトリを管理対象外に設定する事ができました。

Laravelでバッチ処理を実装

はじめに

開発中のシステムで月初に決められた処理を実施するような機能を実装したのでまとめておきます。
定期処理を実施する記述などLaravelを利用するとシンプルに実装する事ができ驚きました。

実装環境

Laravelのバージョンは現時点で最新の8系を利用して動作の確認を行なっています。

実装の手順

以下手順で実装を進める事でバッチ処理を実現します。
1. Aritsanコマンドを自作
2.タスクスケジュールに作成したArtisanコマンドを登録
3.Linuxのcronに登録

では、ここから実際にコードを書いていきます。

Artisanコマンドの自作

Laravelではコマンドファイルの雛形を作成するartisanコマンドが用意されています。以下のコマンドを入力する事でApp/Console/Commandsディレクトリ以下にファイルが作成されます。

$ php artisan make:command [ファイル名]

上記コマンドを入力すると以下の以下のファイルを作成します。(今回は、SampleBatchという名前で作成した例を記載します。)

<?php

namespace App\Console\Commands;

use IlluminateConsoleCommand;

class Sample extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'command:name';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        return 0;
    }
}

各項目の説明

$signature
実行するコンソールコマンドの名前。コンソールにてこの名前で実行する事が可能です。
$description
コマンドの説明文。代入された値は、php artisan listで表示されるArtisanコマンド一覧に表示されます。
handle()
このコマンドを実行したときの処理されます。
続いて作成したファイルに定期実行させたい処理を実際に書いていきたいと思います。

実装例

今回はUserテーブル年齢が20歳以上のデータを全てAdultテーブルに保存する処理を作成してみます。※処理の内容がリアルでない事はご了承ください、、(汗)

<?php

namespace AppConsoleCommands;

use IlluminateConsoleCommand;
use App\Models\User;
use App\Models\Adult;

class Sample extends Command
{
    protected $signature = 'command:adultSave';

    protected $description = '20歳以上のユーザーをAdultテーブルに保存';

    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        $targetUsers = User::where('age', '>=', 20)->get();
        
        foreach ($targetUsers as $user) {
            Adult::create(['name' => $user->name, 'age' => $user->age]);
        }
        return;
    }
}

作成したコマンドは以下のようにコマンドを入力する事でも実行する事が可能です。

$ php artisan command:adultSave

タスクスケジュールに作成したArtisanコマンドを登録

ここまでで実行したい処理の実装は完了しました。次に、定期的に実行するタイミングを指定していきたいと思います。
Laravelでは、app/Console/Kernel.phpのscheduleメソッドに実行したいバッチのコマンド記載していく事で処理を実行するタイミングを指定する事が可能です。

<?php
// ......省略

// 1時間に1回adultSave処理を実行する
protected function schedule(Schedule $schedule)
{
    $schedule->command('command:adultSave')->hourly();
}

実行するタイミングに関しては色々と用意されているので詳しくは公式のドキュメントを確認してみてください。

readouble.com

cronの設定

Laravelのスケジュール登録したのでサーバがLaravelのコマンドを実行してくれるようにcronを設定します。
Laravelのタスクスケジュールを設定する場合は、Cronへのエントリーを1つ加えるだけでタスク毎にCronへのエントリーを追加する必要はありません。

// crontabの編集
$ crontab -e

php /var/www/[プロジェクトフォルダ名]/artisan schedule:run >> /dev/null 2>&1

上記の記述でlaravelスケジューラが毎分実行され、その都度、実行するべきタスクがあれば実行されます。

まとめ

実装前はややこしそうなイメージでしたが結果的には、非常にシンプルに実装する事ができました。
改善箇所などあればコメント頂けますと幸いです。

Laravelでコレクションをfilterする際にインデックスを連番にする方法

はじめに

最近Laravelのコレクションを積極的に使用しています。

readouble.com

filterを使ってフィルタリングする処理を実装した際、インデックスが飛び飛びになり、その後の処理に影響がでてしまう場面が、
今回は、filter使用時にインデックスを連番で返却する方法紹介します。

環境について

動作確認は2021年9月現在で最新のLaravel8系で実施しています。
それ以前のバージョンに関しても同様の方法で対応する事が可能かと思います。

filterの挙動を確認

実際にコレクションを作成し、filterの動きを確認します。

<?php
$foods = ['egg', 'wine', 'pizza', 'apple'];
$fruits = collect($foods)->filter(function ($food) {
  return $food === 'apple';
});

コードの内容はともかく$fruitsを出力してみると以下のようになります。

array (
  3 => 'apple',
)  

インデックスを連番にする

valuesを利用する事でインデックスが振り直されフィルタリング結果を連番にする事ができます。

<?php
$foods = ['egg', 'wine', 'pizza', 'apple'];
$fruits = collect($foods)->filter(function ($food) {
  return $food === 'apple';
})->values();

結果を見ると、、、

array (
  0 => 'apple',
)  

結果を連番で取得する事ができました。
以上になります!