スタイル・エッジ技術ブログ

士業集客支援/コンサルティングのスタイル・エッジのエンジニアによるブログです。

エンジニアも知っていると嬉しいデザインの原則

こんにちは!システム事業部のMJです。
もうすぐ新卒4年目、インターンも含めると5年目になり、年次を重ねるごとにさまざまな経験をさせていただいています。
ここ1年ほど新規事業のシステム開発に携わっていますが、その中で特に記憶に残ったのがシステムのデザインを1から担当したことでした。
(この話をすると、毎日Adobe XDと睨めっこしながら、2ヶ月ほどピクセル単位の修正をしていた記憶が蘇ってきます…)

上記のようにシステムのデザインとまではいかなくても、UI設計を行ったり、プレゼン資料を作成したり…とエンジニアがデザインをする機会は想像以上にあり、デザインの経験がなくても知識を身に付けておくだけで役に立つことがあります。
今回は、知っているだけでドキュメントや成果物のアウトプットが向上するデザイン・設計のテクニックをご紹介します!

ペルソナ設計

ペルソナ(Persona)とは、サービス・商品の典型的なユーザ像のことです。 マーケティングなどでよく聞くペルソナですが、デザインでも必要になってきます。 ペルソナを設定するメリットとしては、

  • プロジェクトの関係者間で、共通した人物像を形成することができる

  • ユーザを具体的にイメージしやすくなるため、製品やシステムが実際に使われている場面をイメージしながらデザインができる

  • その人物像を掘り下げることで需要の高い(低い)コンテンツが見えてくるため、取捨選択など各種判断の材料になる

などが挙げられます。

具体的には、システムのメインカラーを決める際に暖色系か寒色系かで自分とステークホルダの意見が割れたのですが、今回設定した主要なペルソナが20代女性で美容クリニック勤務(以下詳細割愛)だったため、それを根拠に議論を重ね、双方納得する色合いでデザインを進めていくことができました。

このように、デザイン決定の判断軸としてペルソナ視点を用いることでスムーズに問題解決ができたときなどは、ペルソナ設定の重要性を痛感しました…

デザインの4原則

わたしが実際にデザインを担当してみるまでは、デザインというと、色や柄などの美しさのイメージが先行していました。
ただ実際にデザインしてみると、色や柄が美しくてもレイアウトが整っていないと、ユーザに情報が的確に伝わらないということがわかりました。

レイアウトを整えるために重要になってくるのが「デザインの4原則」です!

  • 近接
    関連する要素をまとめることで、グループ化して情報の整理を行う

  • 整列
    要素を意図的に配置してページ上に関連性や統一感を持たせる

  • 反復
    ルールに基づいてデザインの要素を繰り返す

  • 対比
    異なる要素間でサイズや色の強弱を強め、目立たせたい情報を強調する

この4原則を用いることで、論理的にレイアウトを決めていくことができます。

ただし、顧客管理のようなシステムでは情報過多になるため全体的に項目が詰め込まれる傾向にあり、近接・整列・反復は実現できても対比などは難しく苦労しました…
アクセントカラーを決めたり、アイコンを使用するなどして多くの情報の中でも目を引くよう意識しました!

システム開発時に意識するポイント

上記2つのポイントはデザイン全てにおいて基本となる考えですが、システムを開発する際に意識すべきポイントもあります。

流行りのデザインと使いやすいデザインは違うということ

システム事業部にはデザイナーも在籍しているため、おしゃれなデザインやかっこいいデザインを見せていただく機会も多く、システムにも取り入れたいと思ったことが多々ありました…

流行りのデザインは斬新で魅力的に感じますが、ユーザが日常的に使うシステムの場合、デザインによってはユーザが入力する前に考える時間が増えてしまうことがあります。

例えばボタンをアイコンのみで表現した場合、「このボタンはなんのボタンだっけ…?」と悩む一瞬の時間が積み重なってユーザのストレスに繋がりかねないため、デザイン性と利便性を兼ね備える必要があります。

おそらく、流行りのデザインはユーザにとって馴染みがない、システムで使うには情報が省略されすぎている、などの点から使いやすいと言えない場合があるのだと思います。

ターゲットや場面によって「使いやすいデザイン」が変わってくるので、都度判断していくことが大事になります。(この判断軸としてペルソナを用いることも有効)

ユーザレビューを必ず行うこと

これはシステム開発においてどのフェーズでも必要ですが、特にデザインをしていると、自分のデザインしたシステムが自分の「当たり前」になってしまいます。
自分が使いやすいと思ってデザインをしていても、実はユーザの業務都合上項目の配置はこうがいい、といったケースを何度も経験しました。

それだけでなく、世間的にベターとされている手法や理論でさえも、使い方次第ではユーザに受け入れられない場合もあります。
そういった気づきや学びを得るためにも、ユーザレビューは必ず行うよう心がけていました。

おわりに

今回は自分の経験から「エンジニアも知っていると嬉しいデザインの原則」をご紹介しました。
エンジニアとデザイナーは、別分野として捉えがちですが、知っておいたほうがいい知識がたくさんあります。少しでも興味を持つきっかけになれば幸いです!

実はわたしがシステムデザインを担当したきっかけは、色彩検定を取得したことでデザインに興味を持ち、「やってみたい!」と頼み込んだことでした。
やりたいことがあれば、話を聞き、実践する環境を用意し、気にかけてくれる、そんな社風が弊社の素敵なところだなと感じています…!

☆スタイル・エッジ・グループでは、一緒に働く仲間を募集しています☆
もし興味を持っていただけましたら、採用サイト↓も覗いてみてください!
recruit.styleedge-labo.co.jp

CDKでCloudFormation StackSetsのデプロイを行ってみる

はじめに

お世話になっております。システム事業部のONです。
前回の執筆からちょうど2年になります。

中途入社して1カ月でアドベントカレンダー書いてと言われ、2~3カ月で技術ブログを書いてと言われ...
どちらもネタがないとオロオロしながら書いた記憶が鮮明に残っています。
そんな今回もネタがなくオロオロしているので試したかったことを実践してみます。

課題発生

ここ半年程、CloudFormationやSAM, CDKを触ることが多くありました。
これらの沼は深く、私はまだまだくるぶしぐらいしか浸かれていない状況です。

そんな最中、同一AWSアカウントの全リージョンにデプロイする内々のCDKを作る必要が発生しました。
当時はリージョンの配列をループさせて、各リージョンにスタックを作成する形で実装を終えたのですが...
後からCloudFormation StackSetsの存在を思い出し、これを利用すればもっとスマートな形にできたのでは...と疑問が出てきました。

StackSetsとCDK

CloudFormation StackSetsは複数のAWSアカウントやリージョンにスタックを作成できるサービスです。
すなわち、1つのテンプレートで複数のAWSアカウントやリージョンへの一括デプロイをしてくれます。
ドキュメントはこちらから。

StackSets の概念 - AWS CloudFormation https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/stacksets-concepts.html#stacksets-concepts-stackset

AWS Organizationsと組み合わせると、特定のOUに対してデプロイできたりメンバーアカウントが増えた際に自動的に反映してくれたりする、より強力な存在となってくれます。

CDKもAWSの各種リソースをデプロイすることができる仕組みです。
内部的にはCloudFormationが動いていますが、各種言語で定義できることが魅力の一つです。
CDKに関しては、当ブログで紹介している記事があるのでよかったらご参照ください!

AWS CDK入門|準備からサブネットを分けるまで - スタイル・エッジ・グループ技術ブログ https://techblog.styleedge.co.jp/entry/2022/07/19/163825

さて、CDKで定義したリソースを複数のAWSアカウントやリージョンにデプロイするためにStackSetsと連携することはできるのか?というお話ですが...
CDKとStacksetsの連携は残念ながらサポートはされておらず、長い間issueがopenしている状態です。

StackSets Support · Issue #66 · aws/aws-cdk-rfcs · GitHub
https://github.com/aws/aws-cdk-rfcs/issues/66

ただ、このissueのなかでCDKを使ってStackSetsを作成する方法を紹介している方がいらっしゃいました。

https://github.com/aws/aws-cdk-rfcs/issues/66#issuecomment-754599325

せっかくなので、試してみましょう!!

実践編

StackSetsを扱うための準備として、下記2つのIAMロールを作成します。

AWSCloudFormationStackSetExecutionRole
操作するAWSアカウントのAdministratorAccessポリシーを利用できるロール

AWSCloudFormationStackSetAdministrationRole
CloudFormation経由でAWSCloudFormationStackSetExecutionRoleを利用できるロール

作成手順は以下のドキュメントをご参照ください。

Grant self-managed permissions - AWS CloudFormation https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacksets-prereqs-self-managed.html

これらのIAMロールを作成するにあたって「ドキュメントは分割記載されていて分かり辛い!」という方は、CloudFormationのテンプレートも用意されていますのでおすすめです。

https://s3.amazonaws.com/cloudformation-stackset-sample-templates-us-east-1/AWSCloudFormationStackSetAdministrationRole.yml
https://s3.amazonaws.com/cloudformation-stackset-sample-templates-us-east-1/AWSCloudFormationStackSetExecutionRole.yml

それでは、先ほどのissueのコメントにならってCDKの実行ファイルを調整してみます。

調整前のループでスタックを作るコード

// HogeEnvなどをimport(省略)

const app = new cdk.App();

// リージョン毎にスタックを実行(HogeEnvは{ account: xxxx, region: yyyy }の配列)
HogeEnv.forEach(env => {
    new HogeStack(app, 'HogeStack', { env });
});

調整後のStackSetsでスタックを作るコード

// envなどをimport(省略)

const app = new cdk.App();

// デプロイしたいスタックからテンプレート文字列を生成
const stage = new cdk.Stage(app, 'Staging');
new DeployCDKAsAStackSetsStack(stage, 'DeployCDKAsAStackSetsStack', { env });
const stackSetTemplateObj = stage.synth().stacks[0].template;

// StackSetsを作成するためのCloudFormationスタックを作成
const stackSetDeployer = new cdk.Stack(app, 'StackSetDeployer');
// テンプレート文字列を使ってStackSetsを作成
new cdk.CfnStackSet(stackSetDeployer, 'DeployCDKAsAStackSets', {
    permissionModel: 'SELF_MANAGED',
    stackSetName: 'DeployCDKAsAStackSets',
    capabilities: ['CAPABILITY_NAMED_IAM'],
    stackInstancesGroup: [
        {
            deploymentTargets: {
                accounts: [env.account],
            },
            regions: ['デプロイするリージョン', ...],
        },
    ],
    templateBody: JSON.stringify(stackSetTemplateObj),
});

今回は同一AWSアカウント内で複数のリージョンにデプロイするのが目的です。
そのため、デプロイするAWSアカウントはOrganizationsに依存しない形になります。
これらからpermissionModelにはSELF_MANAGEDを設定しました。

StackSetsを作成するためのパラメーターは以下のドキュメントをご参照ください。

class CfnStackSet (construct) · AWS CDK
https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_cloudformation.CfnStackSet.html#autodeployment

デプロイ結果

今回はus-east-1とap-northeast-1の2リージョンを['デプロイするリージョン', ...],に指定します。
実行するとCloudFormationコンソールのStackSetsで2リージョンにスタックが実行されているのが確認できました。

同コンソールのスタック-スタックの詳細ではStackSetsを作成するためのstackSetDeployerスタックが作成され、
その後にStackSets経由で実際にデプロイしたいDeployCDKAsAStackSetsStackスタックが作成・実行されたことがわかります。

最後に

いかがでしたでしょうか?
2023年2月現在CDKのCloudFormation StackSets連携はサポートはされていませんが、
StackSetsを作成するスタックを定義することでCDKからStackSetsの作成ができることが確認できました。

冒頭のCDK内でループさせてスタックを作る方法だと、各リージョンでcdk bootstrapする必要がありました。
また、デプロイコマンドもcdk deploy --allとなって少々力業な感じが否めません。

StackSetsを作成する方法だと、記述量は増えてしまいますがIAMロールを2つ用意するだけで全リージョンのスタックを作成できるためスッキリとした構成にすることができました。
引き続き改善を進めていきたいと思います!

スタイル・エッジ・グループでは一緒に働く仲間を募集しております。
興味をお持ち頂けましたら是非とも下記をクリックしてください↓↓

recruit.styleedge-labo.co.jp

WSLアプリを入れてsystemctlを使おう!

はじめに

こんにちは。システム事業部のTAKです。
私はWindows10内のWSL環境をローカル開発環境として使用しているのですが、従来のWSL環境ではsystemctlが使えなかったため、サービスの登録ができないなど少し残念な思いをしていました。
(なおWindows11&Ubuntu22.04.1であれば、昨年4月頃のWindows Updateにより今回紹介する内容が既に反映されています)

ところが昨年の11月下旬にWSLアプリがMicrosoftストアで正式リリースとなりました。
元々Windowsに入っていたWSLをアプリとして切り出した形になりますが、主に以下のメリットが増えました。

  • systemdが利用できる
  • 機能追加やバグフィックスがOSアップデートを待たなくて済むようになる

ちなみに、既にWSLを入れていた方は以下メッセージがWSL起動時に表示されているかと思います。

LinuxWindows サブシステムが Microsoft Store で入手可能になりました。
'wsl.exe --update' を実行するか、https://aka.ms/wslstorepage にアクセスしてアップグレードできます
Microsoft Store から WSL をインストールすると、最新の WSL 更新がより速く提供されます。
詳細については、https://aka.ms/wslstoreinfo
をご覧ください。

ここまで読んで(察しの良い方はタイトルで)お気づきとは思いますが、Windows環境のみのお話です。
そもそもWSLって何??という方は、すぐ下に公式ドキュメントのリンクを貼っていますので、先に概要を調べてから戻ってきていただけると助かります。

なお、以下に記載しているインストールから設定までの話は、MicrosoftのWSL公式ドキュメントを読めば詳細にすべて書いてあります。
また、wslコマンドのオプションも豊富にありますので、WSLの理解を深めたい方は本記事を読み終わった後に公式ドキュメントも読まれる事をオススメします。

learn.microsoft.com

それでは始めていきましょう!

インストール&設定

前提条件

Windows 10 バージョン 2004 以上 (ビルド 19041 以上) または Windows 11

Microsoftストアよりインストール

Windows Subsystem for Linux
上記リンクのストアページよりWSLアプリをインストールします。はい、完了です。
ちなみに、OS同梱版で動かしていた人もこの手順で移行できます。簡単ですね。
(このペンギンのアイコン、微妙にイラっとするのは私だけでしょうか…?)

systemdのサポート設定

WSLアプリを起動(ターミナル等で起動でもOK)すると、新規の場合はUbuntuのインストール、既に利用している人はそのLinuxOSが起動すると思います。
以下コマンドを実行し、systemdのサポート設定を行います。

$ ls /etc/wsl.conf
# 無ければ作成
$ sudo touch /etc/wsl.conf
$ sudo vi /etc/wsl.conf

wsl.confに以下内容を追記

[boot]
systemd=true

WSL再起動のため、PowerShellより以下コマンドを実行。

wsl.exe --shutdown

再起動後、WSLに入ると以下のようにsystemctlコマンドが使えるようになっていると思います。

systemctl list-unit-files --type=service

これでsystemctlが使えるようになりました!!かんたん!!
WSL内にLAMPなどの学習環境を作った際や、Dockerをインストールした際にsystemctlに登録できない!といった悲しみから解放されます!ヤッター!

と、ここまでの設定手順も公式ドキュメントに記載がありますので、細かい部分についてはそちらをご確認ください。
Windowsフォルダの自動マウント設定の書き方などが載っています。

learn.microsoft.com

systemd設定後にちょっとハマった事

Dockerが起動しなくなった

私の環境ではDocker Desktopを使用せず、WSL内にDockerをインストールしていました。
従来のWSLではsystemctlが使えなかったため、Dockerのdaemonを手動起動させるようにしていた(といっても.bashrcに記載していた)のですが、その設定(/etc/docker/daemon.json)が邪魔してうまく動かなくなってしまったようで…
詳しくはDocker公式ドキュメントを参照してみてください。
同様に、systemctlが動作する状態でdaemon.jsonが残ったままDockerの最新化をしようとすると、エラーを吐いてインストールが失敗するのでご注意ください。

最後に

WSLにより、Windowsでの開発環境構築は一昔前と比べて飛躍的に便利になりました! まだ使った事がない方も、ちょっと使ってみたけどsystemctlが使えず不便に感じていた方も、この記事をきっかけにチャレンジしてもらえると嬉しいです!

スタイル・エッジ・グループでは一緒に働く仲間を募集しております。 興味をお持ち頂けましたら是非とも下記をクリックしてください↓↓

recruit.styleedge-labo.co.jp

アジャイルソフトウェア開発ってなんなのだ。

はじめに

こんにちは、新卒で入社してもうすぐ3年目に突入するみのみのです。

ここ半年ほど、担当プロジェクトの新米PMとして奮闘していました!📚
慣れないながらも試行錯誤し、辿り着いたアジャイルソフトウェア開発について書いてみたいと思います。

世の中のPM業をしている方、だけでなく開発者の方にとっても普段のお仕事の改善に繋がるかもしれません。
最後までお付き合い頂けますと幸いです💌

そもそもアジャイルソフトウェア開発って?

アジャイルソフトウェア開発とは、短期間で実装・リリースを繰り返し、顧客満足度の最大化を図るプロジェクト開発手法です。

そして、アジャイルソフトウェア開発を行う上で重視したいマインドセットとして
アジャイルソフトウェア開発宣言」があります。

アジャイルソフトウェア開発宣言  
私たちは、ソフトウェア開発の実践
あるいは実践を手助けをする活動を通じて、
よりよい開発方法を見つけだそうとしている。
この活動を通して、私たちは以下の価値に至った。
 
プロセスやツールよりも個人と対話を、
包括的なドキュメントよりも動くソフトウェアを、
契約交渉よりも顧客との協調を、
計画に従うことよりも変化への対応を、
 
価値とする。すなわち、左記のことがらに価値があることを
認めながらも、私たちは右記のことがらにより価値をおく。

出典:アジャイルソフトウェア開発宣言

ちょっとわかりにくい表現かもしれませんが、
左記のことがらよりも、右記のことがらを重要視したほうが、不確実な状況下で価値を生み出しやすいというように読み替えるとわかりやすいかもしれません。

また、アジャイルソフトウェア開発宣言の背後には12の原則があります。

アジャイル宣言の背後にある原則  
私たちは以下の原則に従う:
 
顧客満足を最優先し、
価値のあるソフトウェアを早く継続的に提供します。
 
要求の変更はたとえ開発の後期であっても歓迎します。
変化を味方につけることによって、お客様の競争力を引き上げます。
 
動くソフトウェアを、2-3週間から2-3ヶ月という
できるだけ短い時間間隔でリリースします。
 
ビジネス側の人と開発者は、プロジェクトを通して
日々一緒に働かなければなりません。
 
意欲に満ちた人々を集めてプロジェクトを構成します。
環境と支援を与え仕事が無事終わるまで彼らを信頼します。
 
情報を伝えるもっとも効率的で効果的な方法は
フェイス・トゥ・フェイスで話をすることです。
 
動くソフトウェアこそが進捗の最も重要な尺度です。
 
アジャイル・プロセスは持続可能な開発を促進します。
一定のペースを継続的に維持できるようにしなければなりません。
 
技術的卓越性と優れた設計に対する
不断の注意が機敏さを高めます。
 
シンプルさ(ムダなく作れる量を最大限にすること)が本質です。
 
最良のアーキテクチャ・要求・設計は、
自己組織的なチームから生み出されます。
 
チームがもっと効率を高めることができるかを定期的に振り返り、
それに基づいて自分たちのやり方を最適に調整します。

出典:アジャイル宣言の背後にある原則

ここから読み取れる重要なマインドはなんでしょうか。
簡単そうに見えて、やってみると難しいようなマインドです。
・要求の変更を歓迎する
・短い期間でリリースを繰り返す
・開発者とシステムに携わる人は密に連携を行なう
・現場で使えるソフトウェアであることが価値である
・技術的な妥協はしない
・問題を解決するための方法をチームで考え、決定し、臨機応変に変える

これらのマインドを紐解くことで見えた、システム開発の性質は下記と考えました。
・すばやく届ける必要がある。
・システムとは完成するまで不確実なものである。
 なので、変化に対応できるように準備しておく必要がある。
・100%顧客のニーズを捉えた完璧なものを届けることは不可能だ。
 なので、届けた時点において顧客にとって最大限の価値を発揮することを目指す。
・エンジニアは技術職であるからこそ、顧客との意思疎通が難しいことがある。
 なので、連携をとりながらプロジェクトを進めていく必要がある。

すばやく届けるためのプロジェクト計画

アジャイルでは、イテレーションと呼ばれる一定期間の開発サイクルを繰り返し、細かくリリースをします。
そこで、次のイテレーション期間でなにをどうやるかの計画が大切です。

限られたリソースのなかで、どう優先順位をつけるのか。
・要望▶ほぼ無限
・時間▶有限
・予算▶有限
・品質▶有限

答えは「要望」を調節することです。
ときとして要望は大きな「カタマリ」として訪れます。
しかし、その要望すべてが本当に必要なのでしょうか?

本当に必要なものを見極める

「要件」とは「必要な条件」を意味します。
しかし、分厚い要件定義書に書かれている1~2割の機能さえあれば、
案外想定していた通りのビジネス上の利益を得られるといわれています。
では残りの8割はなんなのでしょうか?
これらは、「要件」とは呼べません。

タスクの見積もり

さて、タスクの調節をしたところで、さっそく見積もりをしてみましょう。

どのように見積もるのがよいでしょうか?

アジャイルでは前提として「見積もりはあてずっぽうである」と考えます。
初期段階の、不確かな情報しかないなかで、正確な見積もりは不可能なのです。

リリース間近になって(検証がある程度おわって)だんだんと確実になっていくのです。

相対見積もりのすゝめ

アジャイルソフトウェア開発の名著といわれているアジャイルサムライでは下記のQ.が例に挙げられています。

Q. 8枚のクッキーと10枚のクッキーを食べるのにかかる時間はどのくらいでしょうか?
  1枚のクッキーを食べるのに10秒かかります。

・・・これなら、大体予想がつきますね。
外れたとしても、大幅に外れることはなさそうです。

では、こちらはどうでしょうか?

Q. 風船を6つ膨らませるのにかかる時間は?

Q. 1組のトランプから足りない1枚を探し出せる時間は?

Q. 2つのサイコロを振ってぞろ目を出すのにかかる時間は?

うーん・・なかなかイメージしづらいですね。

このように、人間は相対見積もりならある程度うまくこなせるのです。
「相対サイズで見積もる」というシンプルな原則がアジャイルな見積もりと計画づくりの真髄なのです。

何も基準がないところで、お肉の重さ100gを測るのでは一般人はお肉のプロには勝てませんが
基準のお肉があれば、相対的なお肉の重さを測るとなると、一般人でもプロに劣らない正確さになるそうです。

アジャイルな計画のつくりかた

必要なもの:チームのベロシティ
      タスクの相対見積もり

タスクを優先順に並べて、チームで相対見積もりをしてみましょう。
工数ではなく、相対で見積もるのです。
基準となるタスクを1つ掲げて、それにくらべて大きいか、小さいか、どのくらいの規模感のタスクなのかをざっくりと考えてみます。

私たちのチームではポイント(pt)という単位を使って見積もりをしています。
タスクごとにフィボナッチ数列を使って、プランニングポーカー形式で数字を出し合っています。
プランニングポーカーとは、各自の思うタスクの規模を「せーの」で一斉に提示する工数見積もり手法です。

意見が分かれたら話し合いを行い、最終的なポイントを決めます。
このとき、誰も責めたり、否定したりしてはいけません。
ざっくりとした見積もりのなかで、その人が何を考え、何が見えたのか、素直にきくのです。

こうして見積もったタスクたちを優先順ですすめていきます。

毎月続けると、チームが1イテレーション期間で何ポイントぐらい達成できるか、わかってきます。
イテレーション期間で達成できる範囲のことを「ベロシティ」といいます。

ベロシティの算出と、相対見積もりができるようになれば、プロジェクト計画が上手につくれるようになります。

プロジェクト計画時のポイント

ベロシティ=プロジェクト計画 とするのは危険です。
想定外のタスクや、定型業務のことも見積もりにいれなければなりません。
そうすると、大体プロジェクト計画時はベロシティの4~5割を達成目標とするのがちょうどいいといわれています。

プロジェクト計画がうまくいくために

現在、プロジェクトは計画通り順調に進んでいるのだろうか?
計画ができたら、進捗を把握する必要があります。

進捗を把握するためには、プロジェクトの状況を可視化する必要があります。
可視化の有名な手法としては「カンバン」がありますね。

カンバンは、トヨタ自動車株式会社の生産管理から発祥した管理方式です。
プロジェクト管理においては、チーム全体で個人のタスクを共有して管理する方法として使用され、
「作業前」「作業中」「作業完了」などといったステータスに各タスクを貼り付けて表示します。

私たちのチームでも、各タスクの状態をチーム全員が常に見える状態にし、チームの進捗状況を日々確認するようにしています。
こうすることで、タスクの進捗を調整したり、早い段階で技術的な相談やリリース日の相談、調整ができるようになります。

おわりに

今回は「アジャイルソフトウェア開発」について特にプロジェクト計画部分を紹介しました。

しかし、これらを実践・導入したからといってそのプロジェクトはアジャイル開発手法である、とは言えません。
アジャイルソフトウェア開発の各イベントを実施しているからアジャイル開発なのか? テストを先に書けばテスト駆動開発なのか? そうではないですよね。

アジャイルはあくまでも思想であり、その思想に基づくプラクティスが用意されているだけにすぎません。
世界に同じプロジェクトは2つとないのですから、自分の頭で考え続け、改善を繰り返し続けていくことこそが、アジャイルソフトウェア開発手法のマインドセットだといえます。

参考文献

アジャイルサムライ − 達人開発者への道
著者:Jonathan Rasmusson 著/西村直人・角谷信太郎 監訳/近藤修平・角掛拓未 訳

SCRUM BOOT CAMP THE BOOK【増補改訂版】 スクラムチームではじめるアジャイル開発
著/西村 直人 (著)・永瀬 美穂 (著)・ 吉羽 龍太郎

弊社の風土として

私は、タスク管理業務をしていくうえで、なにかうまいやり方はないかと思い、アジャイルソフトウェア開発に辿り着きました。
提案し、実際に導入していくことができ、日々試行錯誤しながら、よりよいプロジェクトを目指すという経験ができました。

自ら学び、実際に提案し、学んだことを実践してみたい、そんな若手の背中を押してくれる先輩たちがいます😊

☆スタイル・エッジ・グループでは、一緒に働く仲間を募集しています☆
もし興味を持っていただけましたら、採用サイト↓も覗いてみてください!
recruit.styleedge-labo.co.jp

2022年もアドベントカレンダー開催しました!

はじめに

こんにちは!今年スタイル・エッジ・グループに新卒入社したべぷおじです。
入社してもう半年以上経ちました。月日の流れは早いものです…

さて、我々スタイル・エッジ・グループのシステム事業部では、ナレッジを通した社員同士の交流を兼ねてアドベントカレンダーを毎年開催しています。
2022年は総勢59名でアドベントカレンダーを開催いたしました!

そもそもアドベントカレンダーとは?

アドベントカレンダーとは、本来クリスマスまでの期間に日数を数えるために使用されるカレンダーのことですが、 IT業界では12月1日から25日まで1日に1つずつ、技術やマメ知識などを記事として投稿していくイベントのことを指します。

システム事業部では

アドベントカレンダーは、前身のスタイル・エッジLABO時代から数えると、2022年で6年目になります。
今回はクリエイティブチームの合流もあり、参加人数が大幅に増えたので、多い日には1日に件もの記事が投稿されることになりました。

記事が投稿されている様子
今回は記事に関してのコメントをチャットツールの各自の分報チャンネルでやり取りすることになり、毎日たくさんのコメントで盛り上がっていました!
みなさん個性豊かな記事ばかりで毎日とても楽しかったです!

以下、個人的におもしろかった記事をいくつか紹介します。

個人的に面白かった記事の紹介

リバースエンジニアリングについて

バイナリファイルを解析している様子
この記事では、リバースエンジニアリングを活用し、バイナリファイルを解析していました。 エンジニアとして、バイナリファイルを解析できるようになりたいと思いました。

Figmaを使ってアドベントカレンダーを作ってみよう!

完成したアドベントカレンダー
この記事では、Figmaを活用して、おしゃれなアドベントカレンダーを作成していました。 デザインは今後ますます重要になると感じているので、こういったツールも使いこなせるようになりたいですね。

キングオブアドベント

システム事業部では、記事を投稿するだけでなく、全員が投稿し終わったあとにアンケートを集計し、アドベントカレンダーの中で一番よかった記事を決定します。
一番得票数の多かった記事は、キングオブアドベントとして、この上ない栄誉が与えられるのです。

今年のキングオブアドベントは、なんと史上初の2名同時受賞となりました…!
今回はキングオブアドベントを受賞した記事のうち1つを紹介します。

今年もあざざます

モデリングでキャラクターを作成している様子

モデリングでキャラクターを作成する記事で、製作の過程は思わずすごいっ…と声がもれるほどの出来でした。
自分もやってみたいと思えるような素敵な記事だったと思います…!!

もう一つの記事は紹介できませんでしたが、身近な例でRPAの利便性やその魅力が伝わるような面白い記事でした!

まとめ

アドベントカレンダーは、もちろん技術や知識披露の場という面もありますが、 普段あまり関わりのない社員同士での交流の機会にもなっています。

会社としてどんどん規模が大きくなっていきますが、こういった社員同士の繋がりやコミュニケーションは大切にしていきたいです!

最後に

☆スタイル・エッジ・グループでは、一緒に働く仲間を募集しています☆
もし興味を持っていただけましたら、採用サイト↓も覗いてみてください!
recruit.styleedge-labo.co.jp

PHPもアトリビュートでAOP!!

はじめに

こんにちは!未だにPHP8.1で登場したEnumに心躍らせているSHISOです。

さて、今回はJavaのSpringフレームワークでできるアスペクト指向プログラミング(AOP)に憧れ、PHP8.0でリリースされたアトリビュートを使用して同じようにAOPを実現させてみました。
(ちなみにPHP8.0未満であってもLaravel 5.x~8.xをお使いであれば、Laravel-Aspectというパッケージを使ってAOPできるそうなので、興味のある方は試してみてください。)

先に今回の実装サンプル一部をチラ見せすると、クラス内に個別のgetter処理を書かずとも、アトリビュートの指定だけで値参照ができるようになったりします✨

<?php
class ExampleClass extends BaseClass
{
    public function __construct(
        #[Getter] protected string $hoge,
    ){}
}
$exampleClass = new ExampleClass('fugafuga');
// protectedなプロパティなのに 'fugafuga'と出力できる!
var_dump($exampleClass->hoge);

アトリビュートとは

アトリビュートを使うと、 コンピューターが解析できる構造化されたメタデータの情報を、 コードの宣言時に埋め込むことができます。
つまり、クラス、メソッド、関数、パラメータ、プロパティ、クラス定数にアトリビュートを指定することができます。
アトリビュートで定義されたメタデータは、 実行時に リフレクションAPI を使って調べることが出来ます。
よって、アトリビュートは、 コードに直接埋め込むことが出来る、 設定のための言語とみなすことができます。

引用元|https://www.php.net/manual/ja/language.attributes.overview.php

つまり、アトリビュートとはクラスやメソッド・プロパティなどに付与できる追加情報のことです。
このアトリビュートを付与することで、本来のロジックと直接的に関係ない情報を追加できます。

各メソッドやプロパティに付与されたアトリビュートは、リフレクションAPI を使用して取得できるため、アトリビュートの有無や引数から、共通化した処理の対象として扱うか、どういった振る舞いをさせるかなどを判断させることができます。

詳しい使い方はPHPドキュメントを参照ください。

概要

今回はアトリビュートを使用し、getterとトランザクション制御を共通化(分離)してみました。

実装の流れ

  1. アトリビュートを定義
    例: #[Attribute] class Getter {}
  2. 基底クラスやトレイトに共通処理を実装
  3. マジックメソッド内にて、アトリビュートが付与されている対象にのみ(2)の処理を実行するように実装
    例: $reflectionProperty->getAttributes(Getter::class);
  4. 共通処理を付与したい関数やプロパティに、(1)で定義したアトリビュートを指定
    例: #[Getter] protected string $hoge

最終的なコード*1

getter処理を共通化する例

<?php

#[Attribute]
class Getter
{}

/** getter処理を共通化した抽象クラス */
abstract class BaseClass
{
    public function __get(string $name): mixed
    {
        // 指定されたプロパティにGetterアトリビュートが付与されている場合、プロパティの値を返す
        $reflectionProperty = new ReflectionProperty($this, $name);
        $reflectionAttributes = $reflectionProperty->getAttributes(Getter::class);
        if (!count($reflectionAttributes)) {
            return $this->{$name};
        }

        throw new Exception('アクセス不能なプロパティです。');
    }
}

class ExampleClass extends BaseClass
{
    public function __construct(
        // 参照可能にする場合は、アトリビュート#[Getter]を付与する
        #[Getter] protected string $hoge,
    ){}
}

$exampleClass = new ExampleClass('fugafuga');
  // 'fugafuga'と出力される
var_dump($exampleClass->hoge);

トランザクション処理を共通化する例

<?php

#[Attribute]
class Transactional
{
    public function __construct(public readonly bool $needTransaction){}
}

/** 仮DB処理クラス */
class DB
{
    public static function beginTransaction(){}

    public static function commit(){}

    public static function rollback(){}
}

/** トランザクション処理を共通化した抽象クラス */
abstract class BaseClass
{
    public function __invoke(mixed ...$args): mixed
    {
        if (! (method_exists($this, 'handle') && (new \ReflectionMethod($this, 'handle'))->isProtected())) {
            throw new Exception('アクセス権がprotectedのhandleメソッドを定義してください。');
        }

        // Transactional属性を取得
        $handleMethod = new ReflectionMethod($this, 'handle');
        $transactionalAttributes = $handleMethod->getAttributes(Transactional::class);
        if (!count($transactionalAttributes)) {
            throw new Exception('Transactional属性にて、トランザクションの要否を指定してください。');
        }

        $needTransaction = $transactionalAttributes[0]->newInstance()->needTransaction;
        if ($needTransaction === false) {
            return $handleMethod->invoke($this, ...$args);
        }

        try {
            DB::beginTransaction();
            $result = $handleMethod->invoke($this, ...$args);
            DB::commit();
            return $result;
        } catch (Exception $e) {
            DB::rollback();
            throw $e;
        }
    }
}

class ExampleClass extends BaseClass
{
     // トランザクション制御したい場合は、Transactional属性をTrueに
    #[Transactional(true)]
    protected function handle() {}
}

$exampleClass = new ExampleClass();
// トランザクション制御されながらhandle処理が実行される
$exampleClass();

解説

getter処理の解説

1. まずは使用するアトリビュートのクラスを宣言

<?php
#[Attribute]
class Getter
{}

2. Getterアトリビュートの有無でgetter処理を付与する処理を実装

<?php
abstract class BaseClass
{
     // 解説1:アクセス不能(protected または private)または存在しないプロパティを呼ばれた時に実行される「マジックメソッド__get」に処理を実装
    public function __get(string $name): mixed
    {
        // 解説2:リフレクションAPIを使用し、クラスから指定された名前のプロパティを取得
        $reflectionProperty = new ReflectionProperty($this, $name);

        // 解説3:プロパティに付与されているアトリビュート情報のうち、Getterアトリビュートを取得
        $reflectionAttributes = $reflectionProperty->getAttributes(Getter::class);

        // 解説4:Getterアトリビュートが付与されていれば、プロパティの値を返す
        if (!count($reflectionAttributes)) {
            return $this->{$name};
        }

        throw new Exception('アクセス不能なプロパティです。');
    }
}

参考|__get

3. 実際にgetter処理を追加したいプロパティにアトリビュートを設定

<?php
class ExampleClass extends BaseClass
{
    public function __construct(
        // 解説1:クラス内からしかアクセスできないprotected/privateプロパティに#[Getter]アトリビュートを設定
        #[Getter] protected string $hoge,
    ){}

//    // 解説2:本来ならば下記のようなgetter処理が必要
//    public function getHoge(): string
//    {
//        return $this->hoge;
//    }   
}

4. 実行するとエラーにならず値が取得できる

<?php
$exampleClass = new ExampleClass('fugafuga');
 // 'fugafuga'と出力される
var_dump($exampleClass->hoge);

トランザクション処理の解説

1. まずは使用するアトリビュートのクラスを宣言

<?php
#[Attribute]
class Transactional
{
    // 解説1:今回はトランザクション制御の有無を引数で指定できるようにする
    public function __construct(public readonly bool $needTransaction){}
}

2. アトリビュートによるトランザクション制御処理の実装
※ getterの時と同じ解説は省略しています。

<?php
abstract class BaseClass
{
    public function __invoke(mixed ...$args): mixed
    {
        // 解説1:abstractでhandleメソッドの実装を強制すると、引数が自由に指定できないので、こちらの処理で強制
        if (! (method_exists($this, 'handle') && (new \ReflectionMethod($this, 'handle'))->isProtected())) {
            throw new Exception('アクセス権がprotectedのhandleメソッドを定義してください。');
        }

        // 解説2:Transactional属性を取得
        $handleMethod = new ReflectionMethod($this, 'handle');
        $transactionalAttributeArray = $handleMethod->getAttributes(Transactional::class);
        if (!count($transactionalAttributeArray)) {
            throw new Exception('Transactional属性にて、トランザクションの要否を指定してください。');
        }

        // 解説3:Transactional属性のフラグでトランザクション制御
        $needTransaction = $transactionalAttributes[0]->newInstance()->needTransaction;
        if ($needTransaction === false) {
            return $handleMethod->invoke($this, ...$args);
        }

        try {
            DB::beginTransaction();
            $result = $handleMethod->invoke($this, ...$args);
            DB::commit();
            return $result;
        } catch (Exception $e) {
            DB::rollback();
            throw $e;
        }
        $transactionalAttribute = $transactionalAttributeArray[0]->newInstance();
    }
}

3. 具象クラスのhandleメソッドにアトリビュート付与し、実行するとトランザクション制御される。

<?php
class ExampleClass extends BaseClass
{
    // 解説1:Transactional属性とトランザクション制御の有無フラグを引数として設定
    #[Transactional(true)]
    protected function handle() {}
}

$exampleClass = new ExampleClass();
// トランザクション制御されながらhandle処理が実行される
$exampleClass();

終わりに

いかがでしたでしょうか?
アトリビュートを利用したことで、getter処理をプロパティの数だけ書いたり、同じようなトランザクション制御を何回も書く必要がなくなりました。
アトリビュートはあくまで追加情報 ではありますが、今回のように工夫して利用することで、横断的な処理をメイン実装から剥がせたりするので、実務では大いに活躍できそうです。
ぜひ皆さんもアトリビュートを使ってAOPしてみてください!

☆スタイル・エッジ・グループでは、一緒に働く仲間を募集しています☆
もし興味を持っていただけましたら、採用サイト↓も覗いてみてください!
recruit.styleedge-labo.co.jp

参考資料

*1:実行環境:PHP 8.0

流行りのテキストからの画像生成やってみました

はじめに

こんにちは、スタイル・エッジ・グループのぽんです。
今年はオフィス移転の業務に関わったりなど、バタバタしておりましたが…
ようやく、新しいオフィス周辺のお昼の探索を楽しみつつ、
新宿ど真ん中で濡れずに出勤できる喜びを日々かみしめています。

画像生成って?

今回は、ここ最近流行っているテキストからの画像の自動生成を自分の環境で試してみました!
LINEアカウントがあったり、アプリがあったり、色々と盛り上がっていますね。

組み合わせは「VQGAN+CLIP」でWindows環境で実施しています。

「VQGAN+CLIP」であれば、Google Colaboratory(https://colab.research.google.com/)でも可能なのですが
今回はあえて、ローカルPCで実施してみました!

Google Colaboratory(Google Colab)とは、環境構築をしなくても無料で
Pythonでの機械学習のプログラミングが行えるサービスです。
しかもGPUも使用できるため、GPUを積んだPCを持っていなくても実行が可能です。
オンラインベースなので、携帯からでもタブレットからでも
勿論PCからでも操作できるのは素敵ですね!
※より高性能な有料プランもあります。

今回採用した、VQGANはVQ-VAE(ベクトル量子化)を用いた、
敵対的生成ネットワーク(Generative Adversarial Networks通称GAN)です。
GANは、データから特徴を学習し実在しないデータを生成します。そしてそのデータが本物か偽物かの判定を
繰り返すことによって本物のような偽物のデータを作り上げます。

そして、CLIP(Contrastive Language-Image Pre-training)はモデルを持っているわけではなく、
インターネットから画像とテキストの組み合わせを収集することにより、
4億の画像とテキストの組み合わせをOpenAIで学習しています。
テキストのエンコーダとイメージのエンコーダ、それぞれで動作をし、
類似度が最も高い画像をピックアップします。


この2つを組み合わせることによって、入力したテキストから画像の自動生成を実現します!

環境構築と実働

Python 3.10をインストール

まずは、Windowspythonを利用できるようにします。
python
https://www.python.org/downloads/
公式サイトよりダウンロードしてインストーラにてインストールします。

インストールが完了したら、コマンドプロンプトを立ち上げ下記コマンドを実行。

python -v

バージョンがきちんと表示されれば問題ありません。

CUDAインストール

VQGAN+CLIPは、機械学習ライブラリのPyTorchを利用して動作させています。
GPUを積んでいるPCであれば、GPU利用版のPyTorchで動作させたいため…
PyTorchのインストール前にCUDAをインストールします。

CUDAは、NVIDIAGPU向けの統合開発環境です。
私の端末には以前CUDAを入れたことがあるのですが、バージョンが古くてPyTorchの要件に合わないので、
アップデートインストールを行います。

NVIDIAのサイトからCUDA11をダウンロードして、実行します。
CUDA Toolkit 11.8
https://developer.nvidia.com/cuda-downloads?target_os=Windows&target_arch=x86_64&target_version=10

環境変数にパスが追加されているか確認をします。
 システム環境変数の編集 ⇒ 詳細設定 ⇒ 環境変数をクリック

環境変数

CUDA_PATH_V11_8が追加されていることを確認。

コマンドプロンプトで下記コマンドを実行。

nvidia-smi

CUDA Version: 11.XXと表示されることを確認。
これで、無事にCUDAが入りました!

PyTorchインストール

改めまして、PyTorchインストールです。
PyTorch公式
https://pytorch.org/get-started/locally/

公式ページに行き、自分のPC環境に合わせてインストールしたい環境を選ぶと…
環境に合わせたコマンドが表示されます。

私は、condaコマンドで実行しました!
そのためには、前提としてAnacondaのインストールが必要です。

Anacondaインストール

Anaconda
https://www.anaconda.com/products/distribution

公式サイトからパッケージをダウンロード。
そして、インストーラで促されるままにインストール。
Windowsの場合、日本語が入っているフォルダにはインストールが行えないので注意してください。

上記によりAnacondaが無事に入ったので、condaコマンドを手軽に実行するために
スタートメニューで「Anaconda Prompt」を検索して立ち上げます。
そして、PyTorch公式に表示されているコマンドを実行します!

PyTorch公式から環境に合わせてコマンドを取得
conda install pytorch torchvision torchaudio cudatoolkit=11.3 -c pytorch

condaコマンドにて無事にインストールが行えたことを確認したら、
公式に書いてあるコードを実行して確認します。
インストール途中でエラーが出た場合は、周辺コマンドなどのアップデートを適宜行ってください。
※私は、環境が古くて色々アップデートが必要でした。

コマンドプロンプトにて

python

Pythonを起動し入力モードにします。

import torch
x = torch.rand(5, 3)
print(x)

torchを実行!

tensor([[0.3380, 0.3845, 0.3217],
        [0.8337, 0.9050, 0.2650],
        [0.2979, 0.7141, 0.9069],
        [0.1449, 0.1132, 0.1375],
        [0.4675, 0.3947, 0.1426]])

結果が表示されれば無事にインストールはできています。
そして、GPUの利用もできます!
やっとPyTorchが入ったので次に行きます☆

Pythonの追加パッケージをインストール

追加パッケージをpipコマンドでインストールします。

pip install ftfy regex tqdm omegaconf pytorch-lightning IPython kornia imageio imageio-ffmpeg einops torch_optimizer setuptools==59.5.0

VQGAN+CLIPのソースをgitからおろしてきます。

GitリポジトリからVQGAN+CLIPをクローンしてきます。

git clone 'https://github.com/nerdyrodent/VQGAN-CLIP'
cd VQGAN-CLIP
git clone 'https://github.com/openai/CLIP'
git clone 'https://github.com/CompVis/taming-transformers'

クローン出来たら、VQGAN-CLIPフォルダの下に、checkpointsディレクトリを作成します。

VQGANの学習済モデルとyamlファイルをダウンロードします。

curl -L -o checkpoints/vqgan_imagenet_f16_16384.yaml -C - 'https://heibox.uni-heidelberg.de/d/a7530b09fed84f80a887/files/?p=%2Fconfigs%2Fmodel.yaml&dl=1' #ImageNet 16384
curl -L -o checkpoints/vqgan_imagenet_f16_16384.ckpt -C - 'https://heibox.uni-heidelberg.de/d/a7530b09fed84f80a887/files/?p=%2Fckpts%2Flast.ckpt&dl=1' #ImageNet 16384

公式には、curlコマンドでと書いてありますが…
直接ファイルをダウンロードして、checkpointsフォルダ下に
 ・vqgan_imagenet_f16_16384.yaml
 ・vqgan_imagenet_f16_16384.ckpt
という名前で保存しても問題ないです。
curlコマンド環境を整えるのに挫折して…私は直接ダウンロードしました。
 いや、こちらの方がダウンロード速度も早かったです。

動かしてみよう!!!

やっとここまで来ました!
コマンドプロンプトで、VQGAN-CLIPフォルダまで移動しPythonを実行します!

python generate.py -p "A painting of an apple in a fruit bowl"

こちらは、フルーツボールの中にあるリンゴを描いてほしいと命令を出しています。
※VQGAN-CLIPのチュートリアル用画像ですね。
実行が完了すると、同一フォルダにoutput.pngの名前で描いたイラストが出力されました!

フルーツボールの中のリンゴ

やりましたね☆
ようやくテキストから、画像を生成することに成功しました!!

ここで、注意点がありまして…
ローカルで実行してみたいからと言って、GPUを積んでいないマシンで実行をするのは
本当にオススメできません…!

私もこの対応を行う中で、一度、PyTorchの起動に失敗してCPU環境で実行してしまったのですが
GPU環境であれば1分程度で終わる処理が
CPU環境で実行してしまうと、一晩明かしても終わっていませんでした(悲)

色々動かしてみよう!!

折角出来上がった環境なので、他に何枚か描かせてみた画像を添付します。

python generate.py -p "sky and cat and magic"

空飛ぶ魔法ねこみたいなのが描かれたら良いなと思って実行しました!

空とねこと魔法と

割と目的通りな雰囲気は出たかなと思います☆

python generate.py -p "Mechanical robots and programming"

ロボ的な何かが描かれたらと思って実行しています。

ロボとプログラミング

ロボットがプログラミングをしている?みたいになりましたね(笑)

最後に

色々と予想外の仕上がりになるものもあり楽しい結果になりました!
業務には直接関係は無いものの、興味のあるものを環境を作って
実行してみるというのも、なかなか楽しいですね。

スタイル・エッジ・グループでは、色々なことに興味を持ってくれる、一緒に働く仲間を募集しています!
もし弊社に興味を持っていただけましたら、採用サイト↓も覗いてみてください!
recruit.styleedge-labo.co.jp