Yanonoblog!

こつこつと

不変な値を活用してコード設計を行う

はじめに

本記事では「良いコード 悪いコードで学ぶ設計入門」で学んだ内容と別途気になって調べた内容や知識も含めアウトプットしています。

書籍に記載されている内容を順序立ててまとめるというよりは、整理しておきたい周辺の知識と深ぼった内容を雑多に書いています。

書籍ではJavaで説明されていたのですが本記事ではRubyに置き換えながら解説しています。

可変と不変

変数やオブジェクトの値が状態変更できることを可変(ミュータブル)と呼びます。

例えば、配列やオブジェクトの要素の値を変更できる場合、それは可変です。

一方で、状態変更できないことを不変(イミュータブル)と呼びます。

変数やオブジェクトの値が変更不可能であり、一度設定された値は変更できないことを意味します。

適切な設計がされていないとどうなるか

可変と不変が適切に設計されていないと、ある値が特定の状況で変更されることを想定して実装したのに、別の箇所で予期しない値に変わっているといった問題が発生します。

デバッグやメンテナンスの困難さにつながり、開発者が予測できない挙動に悩まされることになります。

上記の問題をなくすには変更を最小限にする設計が重要です。

再代入

変数に再度値を代入することを再代入、または破壊的代入と呼びます。

再代入は変数の意味が変わり、推測を困難にします。また、いつ変更されたのか追うのが難しくなります。

アンチパターン

下記の例では同じ命名の変数に対してパラメータの加算や補正を再代入して使い回されています。

このように途中で変数の意味が変わるとコードの可読性が低下し、メンテナンスや修正をするのが困難になります。。

def damage(member, enemy)
  # メンバーの腕力と武器性能を基本攻撃力として定義
  tmp = member.power + member.weapon_attack

  # メンバーのスピードで攻撃力を補正
  tmp = (tmp * (1 + member.speed / 100)).to_i

  # 攻撃力から敵の防御力を差し引いたのがダメージ
  tmp = tmp - (enemy.defence / 2).to_i

  # ダメージ値が負数にならないよう補正
  tmp = [0, tmp].max

  tmp
end
改善例

可読性を向上させるためには、変数の意味を明確にし、適切な命名規則を使用します。

変数名をより具体的なものにすることで、コードの意図や役割が明確になります。

def damage(member, enemy)
  base_attack = member.power + member.weapon_attack
  speed_modifier = (base_attack * (1 + member.speed / 100)).to_i
  defense_adjustment = (enemy.defence / 2).to_i
  final_damage = [0, speed_modifier - defense_adjustment].max

  final_damage
end

上記のように命名を分けて再代入を行わないのは至極一般的ですが、再代入自体を防ぐ方法もあります。

不変にして再代入を防ぐ

freezeメソッド

Rubyにおいては、変数を不変にするためには freeze メソッドを使用することができます。

freeze メソッドを呼び出すと、オブジェクトが変更できない不変な状態になります。

def do_something
  value = 100
  value.freeze # valueを不変にする

  value = 200 # 実行時エラー(RuntimeError)が発生する
end
不変にするメリット

不変にすると以下のメリットが得られます。

  • 変数の意味が変化しなくなるため、混乱が抑えられる
  • 挙動が安定し、結果を予測しやすくなる
  • コードの影響範囲が限定的になり、保守が容易になる
定数を定義したらfreezeを使う

Railsにおいて定義した定数は基本的にfreezeしておくことが推奨されています。これにより、定数が不用意に変更されることを防ぐことができます。

# 定数の例
POKEMON = ['zenigame', 'fushigidane', 'hitokage'].freeze

定数をfreezeしておくと、その値を変更しようとするとFrozenErrorが発生します。これにより、誤って定数の値を変更することを防止し、予期しないバグの発生を防ぐことができます。

JavaScriptではconstを使用すれば良いだけ

JavaScriptにおいては const キーワードを使用することで変数を不変(再代入不可)にすることができます。

const で宣言された変数は、初期化後に再代入することはできません。

function doSomething() {
  const value = 100;

  value = 200; // エラー: 再代入はできません
}

参考

続く…

コメント

本記事の内容は以上になります!

書籍の続きのアウトプットも随時更新したいと思います。


プログラミングスクールのご紹介 (卒業生より)

お世話になったプログラミングスクールであるRUNTEQです♪

https://runteq.jp/r/ohtFwbjW

こちらのリンクを経由すると1万円引きになります。

RUNTEQを通じて開発学習の末、受託開発企業をご紹介いただき、現在も双方とご縁があります。

もし、興味がありましたらお気軽にコメントか、TwitterのDMでお声掛けください。

https://twitter.com/outputky

デザインパターン(完全コンストラクタ・値オブジェクト)

はじめに

本記事では「良いコード 悪いコードで学ぶ設計入門」で学んだ内容と別途気になって調べた内容や知識も含めアウトプットしています。

書籍に記載されている内容を順序立ててまとめるというよりは、整理しておきたい周辺の知識と深ぼった内容を雑多に書いています。

書籍ではJavaで説明されていたのですが本記事ではRubyに置き換えながら解説しています。

デザインパターン(設計パターン)

ソフトウェア設計において直面する問題を、高凝集化などプログラム構造を改善する設計手法をデザインパターン(設計パターン)と呼びます。

デザインパターンは、ソフトウェア開発の実践的な経験やベストプラクティスに基づいて抽象化され、カタログ化されています。

デザインパターン

本著で紹介されていたデザインパターンの表になります。

完全コンストラクタと値オブジェクトについて本記事で解説します。

設計パターン 簡単な解説
完全コンストラク オブジェクトを生成する際に、すべての必要なパラメータを指定するなどして不正状態から防護する
値オブジェクト 業務で使用される特定の単位や値のルールを高凝集化し、一貫性と信頼性を確保する
ストラテジ 条件分岐を削減し、ロジックを単純化する
ポリシー ドメインや機能に関するルールや条件の振る舞いを単純化したりカスタマイズをできるようにする
ファーストクラスコレクション コレクションを表すクラスで、コレクションに対する操作をカプセル化する
スブラウトクラス スーパークラスから派生したクラスなどで既存のロジックを変更せずに安全に新機能を追加する

完全コンストラク

オブジェクトを生成する際に不正状態から防護するための設計パターンです。

どんな問題解決を解消するか

通常、オブジェクトを生成する際にはデフォルトコンストラクタを使用し、後からインスタンス変数に値を設定する方法が一般的です。

ただ、この方法では未初期化の状態でオブジェクトが生成されて不正な操作やエラーが発生する場合があります。

これを生焼けオブジェクトと呼びます。

生焼けの解決方法

生焼けオブジェクトを防止するにはインスタンス変数をすべて初期化できるだけの引数を持ったコンストラクタを用意します。

コンストラクタ内では、ガード節で不正値を弾きます。

このように設計することで、生成された段階で正常値だけを持つ完全なインスタンスが生成されます。

昨日の記事で紹介したクラスの設計方法がまさに完全コンストラクタを用いたものです。

値オブジェクト

値オブジェクト(Value Object)は、アプリケーション開発において金額、日付、注文数、電話番号など、さまざまな値を扱う際に利用される設計パターンです。

上記のような値を単なる基本データ型ではなく、クラスとして表現することで、各値に関連するロジックを高い結合度でまとめることができます。

どんな問題解決を解消するか

例えば、金額をint型のローカル変数や引数で制御していると、金額計算のロジックが散在してしまい、保守性が低下します。

また、同じint型の「注文数」や「割引ポイント」が、金額用のint型変数に誤って代入される可能性もあります。

解決方法

例えば、金額を表す値オブジェクトでは、加算や減算などの操作をメソッドとして提供します。これにより、金額に関する操作が一つのクラスにまとまり、ロジックの再利用性や保守性が向上します。

値オブジェクトはイミュータブル(変更不可)な性質を持つため内部状態が変更されることはありません。

また、等価性(値が同じかどうか)は値そのものに基づいて判定されます。

下記のコードは、金額を表す値オブジェクトである Money クラスの例です。金額と通貨を保持し、加算・減算・乗算・除算などの操作をカプセル化しています。

class Money
  attr_reader :amount, :currency

  def initialize(amount, currency)
    # 金額が0未満の場合は不正な値として例外を発生させる
    raise ArgumentError, "金額が無効です" if amount < 0
    # 通貨が有効な値かどうかをチェックし、無効な場合は例外を発生させる
    raise ArgumentError, "無効な通貨です" unless valid_currency?(currency)

    @amount = amount
    @currency = currency
  end

  def add(money)
    # 加算対象の通貨が異なる場合は例外を発生させる
    raise ArgumentError, "通貨が一致しません" unless same_currency?(money)

    # 金額を加算して新しい Money オブジェクトを生成して返す
    Money.new(amount + money.amount, currency)
  end

  def subtract(money)
    # 減算対象の通貨が異なる場合は例外を発生させる
    raise ArgumentError, "通貨が一致しません" unless same_currency?(money)
    # 所持金が減算対象よりも少ない場合は例外を発生させる
    raise ArgumentError, "残高が不足しています" if amount < money.amount

    # 金額を減算して新しい Money オブジェクトを生成して返す
    Money.new(amount - money.amount, currency)
  end

  def multiply(factor)
    # 金額を指定した倍率で乗算して新しい Money オブジェクトを生成して返す
    Money.new(amount * factor, currency)
  end

  def divide(divisor)
    # 除算する値が0の場合は例外を発生させる
    raise ArgumentError, "無効な除数です" if divisor.zero?

    # 金額を指定した除数で除算して新しい Money オブジェクトを生成して返す
    Money.new(amount / divisor, currency)
  end

  def equal?(money)
    # 金額と通貨が一致しているかをチェックする
    amount == money.amount && currency == money.currency
  end

  private

  def valid_currency?(currency)
    # 有効な通貨かどうかをチェックするロジック
    # ここでは省略していますが、通貨コードのバリデーションなどが行われる想定です
    true
  end

  def same_currency?(money)
    # 対象の通貨と現在の通貨が一致しているかをチェックする
    currency == money.currency
  end
end

コンストラクタで引数のバリデーションを行い、不正な値を防止します。

また、同じ通貨でない場合や不足している場合には例外を発生させるなど、操作に制約を設けることで不正な状態を防止します。

このように値オブジェクトを利用することで、金額に関するロジックを値オブジェクト内に閉じ込めることができます。

値オブジェクトと完全コンストラクタは得たい効果が近いため、ほぼセットで用いられます。

「値オブジェクト+完全コンストラクタ」は、オブジェクト指向設計の最も基本形を体現している構造のひとつといっても過言ではないと本著では記されていました。

参考

続く…

コメント

本記事の内容は以上になります!

書籍の続きのアウトプットも随時更新したいと思います。


プログラミングスクールのご紹介 (卒業生より)

お世話になったプログラミングスクールであるRUNTEQです♪

https://runteq.jp/r/ohtFwbjW

こちらのリンクを経由すると1万円引きになります。

RUNTEQを通じて開発学習の末、受託開発企業をご紹介いただき、現在も双方とご縁があります。

もし、興味がありましたらお気軽にコメントか、TwitterのDMでお声掛けください。

https://twitter.com/outputky

クラスの適切な設計2

はじめに

本記事では「良いコード 悪いコードで学ぶ設計入門」で学んだ内容と別途気になって調べた内容や知識も含めアウトプットしています。

書籍に記載されている内容を順序立ててまとめるというよりは、整理しておきたい周辺の知識と深ぼった内容を雑多に書いています。

書籍ではJavaで説明されていたのですが本記事ではRubyに置き換えながら解説しています。

クラスベースのオブジェクト指向設計

クラスを定義してそのクラスからオブジェクトを作成することで、プログラムの振る舞いやデータの操作を行います。

データとそのデータを操作するロジックをクラスにひとまとめにし、プログラムの構造を定義していく手法です。クラスが構造の基本単位となります。

Rubyもまたクラス定義や継承、メソッドの定義などオブジェクト指向の機能をサポートしています。

クラス単体で正常に動作するよう設計する

クラスは単体で正常に動作するよう設計し、煩雑な初期設定を必要とせずにすぐに利用できるようにする必要があります。

また、クラスが不正状態に陥ったりバグを生じたりしないように、外部に提供するのは正しく操作できるメソッドのみにするのが基本です。

本著での例えがわかりやすかったため引用します。

ドライヤーには電源のオン/オフスイッチと、風量調節スイッチ、冷風か熱風を切り替えるスイッチが用意されています。これらのスイッチを切り替えるだけで正常に風量や温度を調整可能です。使用者の些細な操作ミスによってドライヤーが破損するほどの風量や温度になることはありません。これらの製品は、それ自体単体で正常に動作するよう設計されています。まどろっこしい初期設定をしたり、ほかの部品と組み合わせないとまともに使えなかったり、ということは基本的にはありません。また、操作方法も、製品が破損しない操作手段が提供されています。

自己防衛責務を持ったクラスが重要です。各クラスは自身の品質を保証し、安全に利用できるようにすることが求められます。個々のクラスが品質的に完結していることで全体の品質が向上します。

適切な初期化ロジック

デフォルトコンストラクタを使用せず、Moneyクラスにすべてのインスタンス変数を初期化できる引数を持ったコンストラクタを実装する例です。

class Money
  def initialize(amount, currency)
    @amount = amount
    @currency = currency
  end
end

これだけでは不十分で、引数に不正な値を渡すことができてしまいます。例えば、次のように不正な値を渡してしまうと、バグが発生する場合があります。

money = Money.new(100, nil)

不正な値が含まれたままプログラムが動作すると、予期しない結果やエラーが発生する可能性があります。

コンストラクタ内にバリデーションを実装し不正な値の場合は例外を発生させるようにします。

正常な値のルールを定義
  • 金額(amount)は0以上の整数であること
  • 通貨(currency)はnil以外であること

これらのバリデーションをコンストラクタに実装した例が以下になります。

class Money
  def initialize(amount, currency)
    validate_amount(amount)
    validate_currency(currency)

    @amount = amount
    @currency = currency
  end

  private

  def validate_amount(amount)
    raise ArgumentError, "金額は0以上の整数である必要があります" unless amount.is_a?(Integer) && amount >= 0
  end

  def validate_currency(currency)
    raise ArgumentError, "通貨はnil以外である必要があります" if currency.nil?
  end
end

このようにバリデーションを実装することで、不正な値が渡された場合に例外が発生し問題を早期に検出できるようになります。

ガード節

上記で解説したコードは初期化の時点でバリデーションのメソッドを呼び出して、例外を洗い出していました。

メソッドの先頭で処理対象外となる条件を定義する方法をガード節といいます。

  def initialize(amount, currency)
    validate_amount(amount)     # バリデーション&処理対象外は例外を返すメソッドを先頭で呼び出す
    validate_currency(currency) # バリデーション&処理対象外は例外を返すメソッドを先頭で呼び出す

ガード節を使用することで、不要な要素を先頭で除外し、後続のロジックをシンプルにすることができます。

コンストラクタにガード節を導入することで、さらなる利点があります。

不正な値が渡されるとコンストラクタで例外がスローされます。これにより、不正な値を持つMoneyクラスのインスタンスが存在できなくなります。

ガード節を使用することで、初期化ロジックがシンプルになり、不正状態に陥る可能性が減ります。正常なインスタンスのみが生成され、安全に利用できるようになります。

参考

続く…

コメント

本記事の内容は以上になります!

書籍の続きのアウトプットも随時更新したいと思います。


プログラミングスクールのご紹介 (卒業生より)

お世話になったプログラミングスクールであるRUNTEQです♪

https://runteq.jp/r/ohtFwbjW

こちらのリンクを経由すると1万円引きになります。

RUNTEQを通じて開発学習の末、受託開発企業をご紹介いただき、現在も双方とご縁があります。

もし、興味がありましたらお気軽にコメントか、TwitterのDMでお声掛けください。

https://twitter.com/outputky

クラスの適切な設計

はじめに

本記事では「良いコード 悪いコードで学ぶ設計入門」で学んだ内容と別途気になって調べた内容や知識も含めアウトプットしています。

書籍に記載されている内容を順序立ててまとめるというよりは、整理しておきたい周辺の知識と深ぼった内容を雑多に書いています。

書籍ではJavaで説明されていたのですが本記事ではRubyに置き換えながら解説しています。

クラス

クラスは、特定の機能や役割を持つコードのまとまりを表現するために使用されます。

Railsにおいては属性(データ)とメソッド(処理)を持ち、オブジェクトを生成することができます。これによってデータとそれに関連する振る舞いを1つのまとまりとして扱うことができます。

モデルクラス

ActiveRecordを継承したモデルクラスは、データベースのテーブルと対応したデータモデルを表現します。

属性はテーブルのカラムに対応し、メソッドはデータの操作やビジネスロジックを実装します。

コントローラークラス

リクエストの受け取りやレスポンスの生成を担当するコントローラークラスは、特定の機能やアクションを実行するための処理を記述します。

リクエストのルーティングやビューへのデータの提供なども行います。

サービスクラス

ビジネスロジックや複雑な処理を切り出して扱うためのサービスクラスは、コントローラーなどから呼び出され、特定のタスクを実行します。

データの操作や外部APIの呼び出しなどを行う場合に使用されます。

適切な設計

HP管理に関するコード

戦闘を伴うゲームなどで、主人公の生命力を表すヒットポイント(HP)以下のように変数で定義されているとします。

hit_point = 100

ダメージを受けてヒットポイントが減少するロジックも必要になりますので以下のように定義します。

hit_point = hit_point - damage_amount
if hit_point < 0
  hit_point = 0
end

「回復アイテムなどで回復する仕様を追加したい」となった場合、以下のような実装がまた必要です。

hit_point = hit_point + recovery_amount
if hit_point > 100
  hit_point = 100
end
アンチパターン

上記で説明したようなコードを分散して定義するとヒットポイントの管理や制約は分散してしまい、重複したコードが発生する可能性があります。

例えば、ヒットポイントの範囲制約を変更する場合には、複数の箇所で修正が必要となります。

さらに、複数のクラスで同様のヒットポイント管理の実装が行われる可能性もあります。

改善例

Railsではオブジェクト指向の原則を活用して、ヒットポイントを表現するクラスを作成することが一般的です。例えば、以下のようにクラスを作成することができます。

HitPointクラスのコンストラクタ(初期化メソッド)において、valueは引数として受け取ります。

class HitPoint < ActiveRecord::Base
    validates :value, presence: true, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 100 }

  attr_reader :value

  def initialize(value)
    validate_value(value)
    @value = value
  end

  # ダメージを受けるメソッド
  def damage(damage_amount)
    damaged = value - damage_amount
    corrected = [damaged, 0].max
    update(value: corrected) # ヒットポイントの値を更新
  end

  # 回復するメソッド
  def recover(recovery_amount)
    recovered = value + recovery_amount
    corrected = [recovered, 100].min
    update(value: corrected) # ヒットポイントの値を更新
  end
end

def validate_value(value)
    unless value.is_a?(Integer) && value >= 0 && value <= 999
      raise ArgumentError, 'ヒットポイントの値は0以上999以下である必要があります'
    end
  end
end
damageメソッド

ヒットポイントを減少させるためのメソッドです。

受け取ったdamage_amountを現在のヒットポイントから引き、その結果をdamagedに代入します。

その後、[damaged, 0].maxでヒットポイントが0未満にならないように修正し、updateメソッドを使ってデータベース上のヒットポイントの値を更新します。

recoverメソッド

ヒットポイントを回復させるためのメソッドです。

受け取ったrecovery_amountを現在のヒットポイントに加え、その結果をrecoveredに代入します。

その後、[recovered, 999].min**でヒットポイントが100を超えないように修正し、**update`メソッドを使ってデータベース上のヒットポイントの値を更新します。

validate_valueメソッド (バリデーション)

コンストラクタでは、0~100の範囲外は不正な値として弾くロジックになっています。

不正な値が紛れ込まないようにしかけをしておくと、バグ化しない頑強なクラス構造になります。このように、意図を持って適切に設計することで、保守や変更がしやすい構造になります。

参考

続く…

コメント

本記事の内容は以上になります!

書籍の続きのアウトプットも随時更新したいと思います。


プログラミングスクールのご紹介 (卒業生より)

お世話になったプログラミングスクールであるRUNTEQです♪

https://runteq.jp/r/ohtFwbjW

こちらのリンクを経由すると1万円引きになります。

RUNTEQを通じて開発学習の末、受託開発企業をご紹介いただき、現在も双方とご縁があります。

もし、興味がありましたらお気軽にコメントか、TwitterのDMでお声掛けください。

https://twitter.com/outputky

ソフトウェア設計 - 低凝集 (アンチパターン)

はじめに

本記事では「良いコード 悪いコードで学ぶ設計入門」で学んだ内容と別途気になって調べた内容や知識も含めアウトプットしています。

書籍に記載されている内容を順序立ててまとめるというよりは、整理しておきたい周辺の知識と深ぼった内容を雑多に書いています。

低凝集 (アンチパターン)

ソフトウェアの設計において関連するデータやロジックどうしが分散し、バラバラになっている状態を指します。

低凝集の状態では、関連する要素がバラバラになっており、一つの機能や目的を果たすために複数の箇所で重複した実装が行われることが多くなります。

主な原因

データとそれを操作するロジックが分離して実装されている場合です。

たとえば、税込み計算のロジックが複数の箇所で独立して実装されている場合、そのロジックの存在を他のメンバーが気づかずに同様の計算を別の場所で行ってしまう可能性が高くなります。

データと計算ロジックが密に結びついていないため、処理の一貫性や保守性が低下し、バグや重複したコードの発生などの問題が生じることがあります。

弊害

重複コード

関連するコードどうしが離れていると、関連するものどうしの把握が困難になります。

既に実装されている機能やロジックが他の開発メンバーに認知されず、同様の機能が別々の場所で重複して実装される可能性が高まります。

修正漏れ

重複したコードが多く存在する場合、仕様変更や修正が必要な場合には、すべての重複コードを特定して変更する必要がありますが、すべての重複コードを把握しづらい状況から修正漏れが発生し、バグの原因となる可能性があります。

可読性の低下

関連するコードや処理が分散している場合、重複コードを含めて関連する要素を特定するために時間がかかります。

特に大規模なプロジェクトでは、複数のモジュールやコンポーネントが組み合わさって動作するため、コードの修正や機能の追加を行う際に、既存のコードの理解や変更箇所の特定がしづらいとさらに時間なかかるでしょう。

低凝集を解消する

低凝集を解消するためには、関連するデータと機能を結びつけることが重要です。

モジュールやクラスの設計を見直す

関連するデータと機能を同じモジュールやクラスにまとめることで、関連性を明確にし、凝集度を高めることができます。

データと計算ロジックを統一的なインターフェースで結びつける

データと計算ロジックを一つのクラスやモジュールで統一的に扱うことで、重複を避け、一貫性のある処理を実現します。

ドメイン駆動設計の原則を適用する

Domain-Driven Designの概念や要件に基づいたモデル化を行い、関連するデータと機能をドメインのコンテキストに結びつけることで、凝集度を高めます。

Railsにおける簡単な例

アンチパターン例 - クラス内に複数の責務が存在する場合

# 低凝集なコード
class User
  def create
    # ユーザーの作成処理
  end
  
  def update
    # ユーザーの更新処理
  end
  
  def delete
    # ユーザーの削除処理
  end
  
  def calculate_score
    # スコア計算の処理
  end
end
改善例 - クラスを責務ごとに分割する
# 凝集性の高いコード
class UserCreator
  def create
    # ユーザーの作成処理
  end
end

class UserUpdater
  def update
    # ユーザーの更新処理
  end
end

class UserDeleter
  def delete
    # ユーザーの削除処理
  end
end

class ScoreCalculator
  def calculate(user)
    # スコア計算の処理
  end
end

アンチパターン例 - メソッド内に複数の役割が混在している場合

# 低凝集なコード
class UsersController < ApplicationController
  def create
    # ユーザーの作成処理
    # ログの出力
    # メールの送信
    # ユーザーのステータス更新
  end
end
改善例 - メソッドを役割ごとに分割する
class UsersController < ApplicationController
  def create
    create_user
    log_output
    send_email
    update_user_status
  end
  
  private
  
  def create_user
    # ユーザーの作成処理
  end
  
  def log_output
    # ログの出力
  end
  
  def send_email
    # メールの送信
  end
  
  def update_user_status
    # ユーザーのステータス更新
  end
end

参考

続く…

コメント

本記事の内容は以上になります!

書籍の続きのアウトプットも随時更新したいと思います。


プログラミングスクールのご紹介 (卒業生より)

お世話になったプログラミングスクールであるRUNTEQです♪

https://runteq.jp/r/ohtFwbjW

こちらのリンクを経由すると1万円引きになります。

RUNTEQを通じて開発学習の末、受託開発企業をご紹介いただき、現在も双方とご縁があります。

もし、興味がありましたらお気軽にコメントか、TwitterのDMでお声掛けください。

https://twitter.com/outputky

AWS - Cloud9

はじめに

インフラの勉強で軽く調べた内容を書き留めておきたいと思いました。

本記事では、主にCloud9に関して調べた内容をまとめていきます。

Cloud9

クラウドベースの統合開発環境IDE)です。

Cloud9はクラウド上で動作する開発環境のため、特定のマシンや場所に依存せずにブラウザかたコードの記述、実行、デバッグを行うことができます。

image

公式の図を参照: https://docs.aws.amazon.com/ja_jp/cloud9/latest/user-guide/welcome.html

AWSのアカウントさえあれば、自分のPCが急に壊れてしまったとしても、違うPCさえあれば開発が進められますね。

機能

ブラウザのみで開発に必要な機能が統括されている(IDE)

コードエディタ、デバッガ、ターミナル、プロジェクト管理などの機能を一つのインターフェースで提供されているため、ローカルのIDE をインストールしたりメンテナンスを行う必要はありません。

Cloud9のコードエディタおよび統合されたデバッガーには、コードのヒント、コード補完等時間を短縮できる機能なども含まれています。

ペアプロがしやすい仕組み

開発環境をチームと共有し、ペアプログラミングを一緒に行うための機能や、IDE内でチャットを開始できる機能があります。

image

公式 参考: https://aws.amazon.com/jp/cloud9/

料金

Cloud9自体は無料で、Cloud9が稼働するEC2の料金だけで利用できるようです。

AWS Cloud9 には追加料金はかかりません。AWS Cloud9 開発環境に Amazon EC2 インスタンスを使用する場合は、コードの実行と保存に使用された コンピューティング とストレージのリソース分 (例: EC2 インスタンス、 EBS ボリューム) のみのお支払いとなります。また、AWS Cloud9 開発環境を、SSH 経由で、追加料金なしで、既存の Linux サーバー (オンプレミスサーバーなど) に接続できます。

料金 - AWS Cloud9 | AWS

続く…

コメント

本記事の内容は以上になります!

書籍の続きのアウトプットも随時更新したいと思います。


プログラミングスクールのご紹介 (卒業生より)

お世話になったプログラミングスクールであるRUNTEQです♪

https://runteq.jp/r/ohtFwbjW

こちらのリンクを経由すると1万円引きになります。

RUNTEQを通じて開発学習の末、受託開発企業をご紹介いただき、現在も双方とご縁があります。

もし、興味がありましたらお気軽にコメントか、TwitterのDMでお声掛けください。

https://twitter.com/outputky

インフラ - Cognito (AWS)の概要

背景

インフラの勉強で軽く調べた内容を書き留めておきたいと思いました。

本記事では、主にCognitoに関して調べた内容をまとめていきます。

Cognito (こぐにーと)

概要

Amazon Cognitoは、ユーザー認証機能を提供するサービスです。

アカウント管理・認証認可の付与をAWS側で行うことができます。

APIベースで実装されるモバイルやWebアプリ向けのユーザー認証で利用されています。

提供機能 - ユーザー認証

ユーザープール

認証・認可を制御するためのメイン機能です。

ユーザーアカウントの作成、ユーザーアカウントの管理、認証を行う機能やトークンの発行及び管理がCognito側で行うことができます。

フェデレーション

外部の認証プロバイダーとの連携を可能にする機能です。

フェデレーションとは、一度認証を行えばその認証情報を使って許可されているすべてのサービスを使えるようにする仕組みのことを指します。

この機能により、ユーザーはGoogleAmazonFacebookなどのアカウントを使用してアプリケーションにログインできます。

Cognito はフェデレーションハブとして、AppleFacebookGoogleAmazon などのソーシャル ID プロバイダーや、SAML や OIDC などのエンタープライズ ID ( プロバイダーを経由したユーザーのログインを可能にします。 ( https://aws.amazon.com/jp/cognito/details/ )

カスタマイズ可能な UI

ユーザーのサインアップとサインインのためのカスタマイズ可能な組み込み UI が用意されています。

基本的にはカスタマイズ前提のようです。

多要素認証 (MFA)

ユーザープールで MFA を有効することで顧客のセキュリティを強化できる機能です。

ユーザーは、SMS や、Google Authenticator などの タイムベースドワンタイムパスワード (TOTP) ジェネレータを使用して自分の ID を確認することができます。

アダプティブ認証

ユーザーのアカウントを保護するための機能です。

新しい場所やデバイスからの試行など通常とは異なるサインインアクティビティが検出されると、そのアクティビティにリスクスコアが割り当てられます。

ユーザーに対して追加の証明を求めるか、そのサインインリクエストをブロックするかを選択できます。

提供機能 - セキュリティ

ボット検出

高度なボット検出機能です。

Amazon Web Application Firewall (WAF) との連携によってサポートされています。

セキュリティ侵害を受けた認証情報の保護

Amazon Cognito は、ユーザーのサインアップ、サインイン、パスワード変更の際に、セキュリティ侵害を受けた認証情報の再利用をリアルタイムで検出し、防止することができます。

他でセキュリティ侵害を受けた認証情報を入力していることが検出されると、パスワードの変更を促されます。

通知方法は、メール、SMS、または他のカスタム通知方法を設定することができます。

Cognitoによる認証・認可の仕組み

基本的には以下の流れで認可・認証の仕組みを実現しています。

ユーザーがURLにアクセスする

アプリケーションは、ユーザーをCognitoの認証エンドポイントにリダイレクトする

Cognitoの認証エンドポイントで、ユーザーがログイン情報を入力するためのログイン画面を返却する

ユーザーは、Cognitoによって提供された認証手段(ユーザー名とパスワード、ソーシャルログインなど)を使用してログインする

アプリケーションは、受け取ったトークンを使用してCognitoに対してユーザーの認可情報やプロフィール情報を要求する

Cognitoは、要求された情報をトークンとともに応答する

(response_type=codeなら認可コード、response_type=tokenならIDトークンとアクセストークンを返却する)

アプリケーションは、受け取ったトークンを検証してユーザー認証を行う

Cognitoの設定

AWS Management Consoleにサインインし、Cognitoのダッシュボードに移動し

ユーザープールの作成を開始するために、「ユーザープールを管理する」をクリックします。

image

ユーザープールの設定画面で、プール名やプールのオプションを設定します。

ここでどの情報を使用してサインインするかなども設定できるようですね。

image

セキュリティ要件を設定します。

柔軟で堅牢なセキュリティを保つための設定ができるようです。 image

サインアップエクスペリエンスを設定します。

image

設定の関係で以降は触れなかったのですが後の手順としては以下になるようです。

メッセージ配信を設定

ユーザープールの作成後、必要なAPIリソースやクライアントアプリケーションにCognitoを統合するための設定

(認証フローの実装や必要なAPI呼び出しの構成の設定ができる)

後はアプリケーション内で実装

(適切なCognito SDKやライブラリを選択し、実装します)

参考

続く…

コメント

本記事の内容は以上になります!

書籍の続きのアウトプットも随時更新したいと思います。


プログラミングスクールのご紹介 (卒業生より)

お世話になったプログラミングスクールであるRUNTEQです♪

https://runteq.jp/r/ohtFwbjW

こちらのリンクを経由すると1万円引きになります。

RUNTEQを通じて開発学習の末、受託開発企業をご紹介いただき、現在も双方とご縁があります。

もし、興味がありましたらお気軽にコメントか、TwitterのDMでお声掛けください。

https://twitter.com/outputky