コンテンツにスキップ

Home

心に余裕がないと何もできない

プロジェクトのマネジメントをしていて、自分の想定通りにいかないことが多く冷静になれないことが多かった。自分が開発する側ならこんなことにはなってないのに、という内容が多くて自分の役割や立場を考えさせられるよいきっかけにもなった気がする。

私はシステム開発は割と好きだし、そのために勉強をすることだってある。でも、周りを見ていると好き好んで勉強する人は少ない。単純に熱量が違う気がいる。この差は大きい。だって、時間が経てば経つほど実力に差がついていくんだから。

だから、自分が思っている速度でメンバーが成長していないことにびっくりするし負の感情が出てくることがある。これじゃいつまでたってもいいシステムは作れないじゃん、って思うし、この会社への不満感にも繋がっている。転職すればいいんだけど、それも億劫な自分がいる。結局、自分がそういう場所を選んでるともいえるので、自業自得なところはあるんだよね。

そういう日々が続いていていると、私生活は家庭のことで精いっぱい。自分のことなんてなかなかできなかった。

それが一区切りつきそうで、気持ちが少し軽くなったので、こんなことを書いてみた。

ブログは雑に書け

個人的にブログを書くって心理的にハードルが高いと感じています。

でも、このツイートを見てもう少し楽に構えようという気になりました。

別に個人運営なんだしまとまってなくても全然いいよね。そりゃそうだ。言語化することが大事だよ。

そう思うことにしました。

日記 - 1か月ぶりに自宅へ帰ってきた

  • 7月10日から妻実家に泊まっていました。約1か月もお世話になっていました。あっという間!
  • 本日は自宅へ帰る日でした。自分だけ先に帰って、妻&子どもは翌日に帰宅します
  • 電車で網棚に置いた荷物を取り忘れてしまった…JRから連絡があって郵送で届けてくれるとのこと。ラッキー!
  • 帰宅して速攻で大きいものの洗濯しました。ソファーカバーとか。ずっと洗ってなかったし子どもが使うので。
  • めっちゃ久しぶりにパソコン触った。1か月も使わなかった日って今までなかったんじゃないかな?
  • ビール飲みながら書いてます

Line Messaging APIを使って画像・動画を取得する

意外とMessaging APIについての情報が少ないので、メモとして残しておきます。

先にやっておくこと

  • Line DevelopersからMessging APIのチャネルを作っている
  • Webhook設定済みである
  • 私はLambdaの関数 URLを設定して確認した
  • そのため、サンプルコードもLambda前提である
  • チャネルアクセストークンを発行済みであること

サンプルコード書いていますが、そこではS3を使っています。必要に応じてその辺の設定もしてください。

手順

  1. Lineから作っておいたチャネルを友だち登録する
  2. チャネルに画像または動画を投稿する

そうすると、LineからWebhookへリクエストされます。

サンプルコード

以下は、Lineからデータを取得してS3にアップロードするLambda + Pythonのサンプルコードです。

import json
import os
import urllib.request

import boto3

CHANNEL_ACCESS_TOKEN = "your token"
S3_BUCKET = "your bucket"

def lambda_handler(event, context):
    print(json.dumps(event))

    for message_event in json.loads(event["body"])["events"]:
        message_type = message_event["message"]["type"]

        # 画像・動画以外は受け付けない
        if message_type not in ["image", "video"]:
            continue

        message_id = message_event["message"]["id"]

        # 画像・動画ファイルを取得する
        content = fetch_content(message_id=message_id)

        # 画像・動画ファイルをS3にアップロード
        original_filename = os.path.join("original", message_id)
        upload_s3(bin=content, filename=original_filename)

        # プレビュー画像を取得する
        preview_content = fetch_preview_content(message_id=message_id)

        # プレビュー画像をS3にアップロード
        preview_filename = os.path.join("preview", message_id)
        upload_s3(bin=preview_content, filename=preview_filename)

    return {"statusCode": 200, "body": json.dumps("Hello from Lambda!")}


def fetch_content(message_id: str) -> bytes:
    url = f"https://api-data.line.me/v2/bot/message/{message_id}/content"
    return request_get(url=url)


def fetch_preview_content(message_id: str) -> bytes:
    url = f"https://api-data.line.me/v2/bot/message/{message_id}/content/preview"
    return request_get(url=url)


def request_get(url: str) -> bytes:
    headers = {
        "Content-Type": "application/json; charset=UTF-8",
        "Authorization": f"Bearer {CHANNEL_ACCESS_TOKEN}",
    }
    req = urllib.request.Request(url, method="GET", headers=headers)
    with urllib.request.urlopen(req) as res:
        return res.read()


def upload_s3(bin: bytes, filename: str) -> str:
    s3 = boto3.resource("s3")
    bucket = s3.Bucket(S3_BUCKET)
    bucket.put_object(Body=bin, Key=filename)

eventログ

body部分だけ参考として載せます。

画像

{
  "body": "{\"destination\":\"U668a9c2c0b1469cd8d5e984672961913\",\"events\":[{\"type\":\"message\",\"message\":{\"type\":\"image\",\"id\":\"463074078431562241\",\"contentProvider\":{\"type\":\"line\"}},\"webhookEventId\":\"01H4VG23S8TRNE9XJVEEE3HHFP\",\"deliveryContext\":{\"isRedelivery\":false},\"timestamp\":1688844963119,\"source\":{\"type\":\"user\",\"userId\":\"U0b465adc30fb8ac1fc6a414d06a0b1c7\"},\"replyToken\":\"fc66ac7d07bb408aa0f272cfb384d0f8\",\"mode\":\"active\"}]}"
}

動画

{
  "body": "{\"destination\":\"U668a9c2c0b1837cd1d5e984672961913\",\"events\":[{\"type\":\"message\",\"message\":{\"type\":\"video\",\"id\":\"463076447542233697\",\"duration\":34208,\"contentProvider\":{\"type\":\"line\"}},\"webhookEventId\":\"01H4VHD7F932NQFT58QE4FCB13\",\"deliveryContext\":{\"isRedelivery\":false},\"timestamp\":1688846375921,\"source\":{\"type\":\"user\",\"userId\":\"U0b465adc30fb8ac1fc6a414d06a0b1c7\"},\"replyToken\":\"e2b900a4dbef4f088a70d0097873dc60\",\"mode\":\"active\"}]}"
}

ドキュメント

  • https://developers.line.biz/ja/reference/messaging-api/#getting-content

育児休暇をとった

2023年6月某日に娘が産まれました。結婚してから約6年、2人にとっては念願の子供です。

長かった。私も妻も結婚したら何事もなく子供が産まれると思っていました。でも、うまくいかない時期が続きました。とくに妻は相当大変だったと思います。

  • いくつかの大学病院で検査した
  • 漢方を試した
  • 不妊不育治療のクリニックに通った

など、いろいろ試行錯誤しました。

また、2022年には東京から岐阜に引っ越しました。周りに友だちがいない環境です。しかし、いい影響を与えたと2人とも感じています。

こんなことをしながら、ようやくの出産です。本当に良かった。

7、8月の2か月の間、育児休暇を取ります。良き父親になれるよう精進したいと思います。

ChatGPTにMarkdown記法の例を書いてもらった

このサイトのスタイルを確認したかったので、ChatGPTに確認用のテキストをMarkdownで生成してもらいました。

生成時に指示した内容はこれです。適当です。 「Markdown記法をふんだんに使った文章を作成してください。内容は問いません。」

自分で考えるのがめんどくさいときにGPTを利用するのは非常に楽でいいですね!


見出し

これは見出しの例です。Markdown では、# の数で見出しのレベルを指定します。

リスト

以下はリストの例です。

  • 項目1
  • 項目2
  • 項目3

番号付きリストの例もあります。

  1. 1つ目の項目
  2. 2つ目の項目
  3. 3つ目の項目

強調

斜体太字 のテキストを使用することもできます。

リンク

リンクのテキストを作成するには、角かっこ [ ] と丸かっこ ( ) を使用します。

[リンクのテキスト](https://www.example.com)

画像

画像を表示するには、次のように書きます。

![代替テキスト](https://blog.mah.blue/next.svg)

代替テキスト

引用

引用を表すためには、行の先頭に > を追加します。

引用の例です。引用文はこのように表示されます。

コード

コードのブロックを表示するには、バッククォート ` を使用します。

print("Hello, World!")

表を作成するには、パイプ | とハイフン - を使用します。

| 名前 | 年齢 | | ---- | ---- | | 田中 | 25 | | 山田 | 30 | | 佐藤 | 28 |

名前 年齢
田中 25
山田 30
佐藤 28

これらは Markdown 記法の一部の例です。Markdown を使用すると、テキストを簡単に整形して見やすくできます。


これは追加のパラグラフです。Markdown はテキストの書式設定や整形を行うための便利な方法です。シンプルで読みやすく、さまざまな要素を組み合わせることができます。見出しやリスト、強調、引用、コードブロック、表など、さまざまな要素を活用できます。また、リンクや画像の挿入も簡単に行うことができます。Markdown を使えば、文書を見やすく整理し、情報をわかりやすく伝えることができます。

さらにもう 1 つのパラグラフです。Markdown は多くのプラットフォームやツールで広くサポートされています。メモやドキュメント、ブログ記事、README ファイルなど、さまざまな場面で活用できます。記法も比較的シンプルで覚えやすく、初心者にも取り組みやすいです。Markdown を使って情報を整理し、魅力的な文章を作成しましょう。

CypressでE2Eテストのカバレッジを測定する

Next.js で作成したアプリケーションに対して Cypress を使って E2E テスト実施時にカバレッジを測定するようにしました。

ライブラリの追加

npm install -D @cypress/code-coverage babel-plugin-istanbul

インストール後

package.json

  "dependencies": {
    "next": "13.0.6",
    "react": "18.2.0",
    "react-dom": "18.2.0",
  },
  "devDependencies": {
+   "@cypress/code-coverage": "^3.10.7",
+   "babel-plugin-istanbul": "^6.1.1",
    "cypress": "^12.5.1",
  }

ライブラリを使うための設定

ファイルを作成する

以下にファイルを作成してカバレッジを測定するための設定をします。

cypress/support/e2e.js

import "@cypress/code-coverage/support";

.babelrc

{
  "presets": ["next/babel"],
  "plugins": ["istanbul"]
}

pages/api/__coverage.js

module.exports = require("@cypress/code-coverage/middleware/nextjs");

Server Side のコードカバレッジを取得するために、@cypress/code-coverageプラグインはエンドポイントを必要とします。このエンドポイントは、Next.js の API 規約にしたがって pages/api/coverage.js ファイルに実装されています。このエンドポイントは、既存のグローバルカバレッジオブジェクトを返すか、NULL を返すだけです。

設定ファイルの追記

Cypress プラグインは、cypress.config.json ファイルから環境変数を使用して正しいエンドポイントを要求します。

cypress.config.js

module.exports = defineConfig({
  e2e: {
    setupNodeEvents(on, config) {
      require("@cypress/code-coverage/task")(on, config);
      return {
        ...config,
      };
    },
    baseUrl: "http://localhost:3000",
  },
  env: {
    codeCoverage: {
      url: "/api/__coverage__",
    },
  },
});

役に立ったドキュメント

CodeBuildでdocker-composeを立ててpytestを実施する

ユニットテストは書いているけど CI で回せていなかったので、ビルド時にユニットテストを実行する設定しました。

環境

  • ビルドは Chalice を使って書いたコード
  • パッケージ管理は pipenv
  • Lambda のランタイムは Python3.9
  • pytest でテスト
  • データベースとの接続部分は docker でテスト用の DB サーバを立てている

ディレクトリ構造

.
├── Pipfile
├── Pipfile.lock
├── app.py
├── buildspec.yaml
├── chalicelib
├── docker-compose.yml
├── pytest.ini
└── tests

buildspec.yaml

version: 0.2
phases:
  install:
    runtime-versions:
      python: 3.9
    commands:
      - export LANG=ja_JP.utf8 # warning が出てたので設定したけどなくてもよい
      - pipenv sync --dev
  pre_build:
    commands:
      - export VENV_HOME_DIR=$(pipenv --venv)
      - . $VENV_HOME_DIR/bin/activate
      - docker-compose up -d
  build:
    commands:
      - python3 -m pytest tests
    on-failure: ABORT
artifacts:
  files:
    - "**/*"

つまずいた点

docker-compose up -d でエラーになる

原因

コマンド実行権限がないため。CodeBuild の作成時の設定ミスです。

解決策

CodeBuild 設定の環境特権付与にチェックします。

docker-compose 時に too many requests が発生した

原因

Docker Hub の制限のため。

Step 1/2 : FROM postgres:13.3 toomanyrequests: You have reached your pull rate limit. You may increase the limit by authenticating and upgrading: https://www.docker.com/increase-rate-limit Service 'postgresql' failed to build : Build failed

classmethod さんの記事“Too Many Requests.” でビルドが失敗する…。AWS CodeBuild で IP ガチャを回避するために Docker Hub ログインしよう!という話が参考になります。

解決策

Amazon ECR Public Galleryからイメージを pull するように変更します。

ただし、以下の制限があるようです。あまり気になりませんが、注意しておきましょう。 https://aws.amazon.com/jp/blogs/news/docker-official-images-now-available-on-amazon-elastic-container-registry-public/

Amazon ECR Public から任意の AWS リージョンにイメージをプルするお客様は、事実上無制限にダウンロードできます。AWS 外で動作するワークロードについて、AWS 上で認証されていないユーザーは毎月 500 GB のデータダウンロードが可能です。さらにデータをダウンロードしたい場合は、AWS アカウントにサインアップまたはサインインすることで、毎月 5 TB までのデータをダウンロードすることができ、その後は 1 GB あたり 0.09 ドルの料金が掛かります。