2024/11 CTOへの日報まとめ

日報




2024-11-5

SeleniumにてDOMの存在確認を行う際に使用するpresence_of_element_locatedの挙動を理解することができました。

presence_of_element_locatedは、特定の条件に一致する最初の1つの要素が存在することを確認する

WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, “.class_name”)) )

上記の場合、クラス名がclass_nameの最初の要素がDOMに存在するまで待機する

これにより、例えば、WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, “table > tr”)) )とした場合、最初のtrがDOMに存在することを確認したら待機が終了し、後続のコードへと移行する挙動をとることを知りました

そのため、全てのtrがDOMに存在することを確認してから後続のコードの実行へと移りたい場合は、presence_of_element_locatedではなく、presence_of_all_elements_locatedを使用するべきであることを知りました。

presence_of_all_elements_locatedは、条件に一致する全ての要素がDOMに存在することを確認するまで待機する挙動をとるとのことでした。

2024-11-6

複数のdocker compose間で通信する方法を知ることができました。

1、共有ネットワークの事前作成

まずホスト側でネットワークを作成する。はじめに一度だけ手動で以下のコマンドを実行する。

docker network create sample_network

2、各docker-compose.ymlにて、下記のようにネットワーク定義を記述

services:
# 色々とコンテナを定義
networks:
sample_network:
external: true

  • external: true を設定すると、Composeは指定したネットワークがホスト側に既に存在するものとして扱う
  • Docker Composeは、独自のネットワークを作成せず、指定された既存ネットワークにサービスを接続する
  • これにより、各docker composeが管理している複数のコンテナが、1つの同じネットワーク(sample_network)に参加できるようになる
2024-11-7

dockerのマルチステージビルドについて知ることができました。

マルチステージビルドとは、1つのDockerfileの中で複数のビルドステージを定義し、各ステージで異なるベースイメージを使用することで、最終的に1つのコンテナイメージを生成される仕組み

(具体例)
FROM golang:1.20 as builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -o main .

FROM alpine:latest
RUN apk –no-cache add ca-certificates
WORKDIR /root/
COPY –from=builder /app/main .
CMD [“./main”] EXPOSE 8080

上記では、1つ目のビルドステージにて、goのベースイメージを使用して、Goコードをビルドしている。そして、2つ目のビルドステージにて、1つ目のビルドステージで生成したビルド後ファイル(バイナリ)をalpineイメージ上で実行している。goコードのビルドには、goのコンパイラが必要になるため、ここではベースイメージとしてgoのイメージを使用。しかし、ビルド後ファイルはただのバイナリなので、バイナリの実行に必要な環境さえ用意できればよく、そこで2つ目のビルドステージにて、そのバイナリを軽量なalpineイメージ上で動かすように指定。これにより、バイナリ実行環境に余計なライブラリが混入することが防がれ、セキュリティ面でのメリットを享受しつつ、軽量なコンテナを実現できる。

2024-11-11

jsのscriptタグにdeferを指定した場合の挙動について知ることができました。

defer属性を指定した場合の scriptタグの挙動は以下の通り

1、非同期で読み込まれる

deferが指定されたスクリプトは、HTML文書の解析と並行して非同期的にダウンロードされる。つまり、HTMLのパースをブロックせず、ページの読み込み速度を維持できる。

2、HTML の解析後に実行される

defer属性を指定したスクリプトはHTML 文書の全体のパースが完了した後に実行される。つまり、スクリプトはページのDOM全体が構築されてから実行されるため、スクリプト内でDOM操作を行う際に、DOMの準備が整っていることが保証される。

3、指定された順に実行される

defer属性を持つ複数のスクリプトは、HTMLドキュメント内に記述された順番通りに実行される。これはasync属性と異なる点(async はスクリプトの読み込みが終わり次第、順番を無視して実行される)

この場合、script1.js と script2.js は並行して読み込まれるが、HTML の解析が終わった後に、記述された順に実行される。

defer 属性は、ページのパフォーマンスを向上させつつ、DOM の読み込み後にスクリプトが実行されることを保証したいときに便利。

2024-11-12

npm run dev により、buildをdevモードでやると、ブラウザでデバッグしやすいことを知りました。

2024-11-15

AWSのENIについて理解することができました。役割やユースケースなど色々と知ることができましたが、まとめると「VPC内のリソースが通信を行うために必要な部品であり、これがあることでセキュリティグループによるリソース単位でのトラフィック制御やネットワークACLによるサブネットレベルでのトラフィック制御、またNAT Gateway, Elactic IPによるIP固定化といった通信に関するあらゆる設定が適用可能なる部品」ということで理解しました。

2024-11-18 ①

VPCの外にLambdaを配置することによるセキュリティの懸念について調べました。

1、インターネット通信の制御が限定的

  • Lambdaがインターネットへ直接アクセスする形になるため、トラフィックのルーティングや監視が難しくなる
  • 外部通信における細かなアクセス制御(例:セキュリティグループやネットワークACLを使った制限)が行えない

2、プライベートリソースとの接続が制限される

  • VPC外部にLambdaがある場合、VPC内のリソース(RDSやプライベートサブネット内のEC2インスタンス等)に直接接続することが難しく、必要に応じてVPCエンドポイントやAWS PrivateLinkを追加で設定する必要がある

3、セキュリティログの追跡が限定される

  • VPCフローログを活用できないため、Lambdaの通信経路を追跡するのが難しく、トラフィック分析や問題発生時の原因特定が困難になる

VPC外にLambdaを配置する方法は、シンプルで手軽だが、セキュリティ上の制約等がある。一方、VPC内で運用する方法は、少し構成が複雑になるものの、セキュリティや運用面での柔軟性が大幅に向上する。状況に応じて、どちらかを選択するべきである。

2024-11-18 ②

Fuelでのcsrfトークンはリクエスト毎に一意かと思いますが、Laravelではセッション毎に一意です。同じ言語の同じMVCという設計のフレームワーク間でも違いがあることに面白さを感じました。セッションのデフォルト有効期限がFuelでは24時間かと思いますが、Laravelは2時間です。ここらへんも関係しているのかなと思いました。

2024-11-19

POSTからGETに変換することで、データをクエリパラメータで送る形になりますが、それにより意図せずにデータが変換されて送られることを知りました。クエリパラメータは文字列なので、boolやnullはそのままの型では送られないことは確かに納得であり、対応が必要ということが分かりました。

2024-11-21

ブランチに特定のコミットだけをピックアップして適用するcherry-pickの存在を知ることができました。

2024-11-22 ①

文字列がJSONかどうかを判定する1つの方法を知ることができました。下記のように実際にデコードしてみて、エラーが起きなければJSONと判定する方法です。

function isJson($string) {
  json_decode($string);
  return json_last_error() === JSON_ERROR_NONE;
}

ただし、形式的にはJSONだが期待するデータ構造ではない場合(例えば、”123″ も有効なJSONだが、特定の形式(オブジェクトや配列)を期待する場合)には、下記のように追加の判定が必要でした。

function isJsonObjectOrArray($string) {
  $data = json_decode($string, true);
  return json_last_error() === JSON_ERROR_NONE && (is_array($data) || is_object($data));
}

2024-11-22 ②

あまり考えたことがなかったのですが、PHPの json_decode() 関数は、デコードに失敗してもエラーを発生させるわけではないことを知りました。代わりに、失敗した場合は null を返すだけで、エラーの詳細は json_last_error() を使用して確認できることを知りました。

2024-11-25 ①

Gitのpre-commitフックについて知ることができました。

Gitのpre-commitフックとは、コミットが実行される前に特定のスクリプトを実行するための仕組み。これにより、コミットメッセージのフォーマット確認、コードの品質チェック、Lintツールの実行、テストの実行など、自動化タスクを組み込むことができる。

pre-commitフックの概要

  • タイミング:git commitコマンドが実行される直前に実行される
  • 目的:コードのチェックやフォーマット、テストの実行、コミットを防ぐ条件の設定など
  • ファイル場所:Gitリポジトリの .git/hooks/pre-commit ファイル
  • スクリプトの内容:シェルスクリプトやPythonなどで記述可能
2024-11-25 ②

fuel/app/config/session.phpのgc_probabilityにて、ガベージコレクションの実行確率を調整できることを知りました。

‘gc_probability’ => 5, // 5%の確率でガベージコレクションを実行

2024-11-26

XPathについて知ることができました。

  • XPath(XML Path Language)とは、XML文書内の要素や属性を効率的に検索、選択するためのクエリ言語
  • HTML文書の解析にも利用され、特にウェブスクレイピングや自動化ツール(Selenium等)で広く使われている
2024-11-27

FuelPHPでイベントを登録できることを知りました。

  • FuelPHPでは、イベント駆動型のアプローチを採用しており、特定のイベントが発生した際に実行する処理を登録できる
  • bootstrap.phpでこれらのイベントリスナーを登録する

FuelPHPに組み込まれている標準イベントの例

fuel.startup

  • フレームワークの初期化処理が始まるときにトリガーされる
  • 例:デバッグやログの初期化

fuel.before

  • アプリケーションがリクエストを処理する前にトリガーされる
  • 例:リクエストデータの検証やグローバル設定の適用

fuel.routing

  • ルーティングが決定された直後にトリガーされる
  • 例:特定のルートに基づいた動的な設定変更

fuel.controller_started

  • コントローラーがインスタンス化されたときにトリガーされる
  • 例:コントローラー全体に適用する前処理

fuel.shutdown

  • フレームワークが終了するときにトリガーされる
  • 例:リソースのクリーンアップ処理

\Event::register(‘fuel.before’, function () {
// グローバル設定の適用
});

2024-11-28

FuelPHPでカスタムイベントを登録する方法を知ることができました

// カスタムイベントのリスナーを登録
\Event::register(‘custom.event’, function ($data) {
  \Log::info(‘Customイベントが実行されました: ‘ . json_encode($data));
});

// イベントをトリガー
\Event::trigger(‘custom.event’, [‘key’ => ‘value’]);

2024-11-29

FuelPHPにて、同じイベントに複数のリスナーを登録した際の挙動について知ることができました。

// リスナー1
\Event::register(‘custom.event’, function () {
  \Log::info(‘リスナー1が実行されました’);
});

// リスナー2
\Event::register(‘custom.event’, function () {
  \Log::info(‘リスナー2が実行されました’);
});

// イベントをトリガー
\Event::trigger(‘custom.event’);

// 出力
リスナー1が実行されました
リスナー2が実行されました