気まぐれ日記(2/11)「休日を満喫した!とは言えないかも…」

気まぐれに日記上げていきたい所存

やったこと

  • 13時に起きたけどダラダラとYoutubeのショートを見てた。設定セブンのショートおもろい
  • 15時にベッドから出てUberでスタバのラテとチョコパイとチョコクッキーとパン?のおやつ食べた。(お金使い過ぎ)
  • そのあとはPath of the Abyssっていうダンジョンゲーやったけど、全滅したら最初からのゲームで2回全滅した。。時間を浪費した感覚が強い。考えて進める必要のあるゲームで自分は対人ゲー以外は頭使わずにやりたいからちょっと合わんかも。
  • ゲーム続きでLoLをやった。クイック2戦、ランク2戦で全部ADCをやった、クイックの2戦目で対面にエメラルドが来てボコられたからランク行った(今期初)。 ランクは2戦とも勝った、でも相手のミスを拾っただけで自分が上手く動けた感覚は無い、レーン戦でのデスが多くて、CSもほとんど取れてない感覚があるから次は意識しよう。
  • そのあとはランニングをした、つい最近初めて今日で二回目。一回目よりも余裕を持って走れたからほんの少しだけ距離を伸ばした。今日は1.4km、5分(目標は5km、20分)。走る前にコースを決めるほうがゴールを意識できるから次はそうする。(ランニングコース決めて案内してくれるアプリないかな?)
  • お風呂入ったあとはchibivueをやろうと思ったけどvueのチュートリアルから始めた。いまは宣言的レンダリングで出てきたJavaScriptのProxyオブジェクトの理解が浅いと感じたのでそこを勉強してる。しゃろうさんの音楽聞きながらやったけどいい曲すぎてノリノリになって余り進まんかったw
  • んで、今日記を書いている(23時)。LoLのランクやるか勉強するか。。。むずかしい。。。明日のこと考えて寝よかな。よし寝よう!!!(寝れるかわからんけど)

反省

  • 起きるの遅すぎ。。。
    • 朝早く起きてもやることがないと考えて、二度寝を繰り返しちゃう。絶対にやらないといけないことを朝に用意しとくのはありかもなぁ
    • あとは、生活習慣か。。。同期とかは遅くても9時には絶対ベッドから出てるらしいし。
  • ゲームやってるのは良し!趣味やからね。休日やから問題ないはず。できれば技術を高めるためにもっと学びの時間を増やしたいところ
    • 学びをアウトプットして楽しいと感じた体験が少ないから、積極的にアウトプットすべきかも。
  • 作業効率を上げるために音楽は聴かない方が自分はいいかも。ただ、無音は集中力逆に切れそうに感じてる。。。まぁ色々試そう。
    • パターン上げするなら無音、ホワイトノイズ、BGM、海外の歌、逆に自分の好きな歌とかかな?
  • 3年たって知ってること増えたつもりやけど、Proxyオブジェクトすら理解がおぼつかないとは。。。自省の念を覚える。。精進しよう。
    • 自分のことをポジティブに弱いと意識することを心掛けようかな?(弱いというより謙虚な気持ちか)

明日、来週やること

  • 明日はどうしようかな?Vueの勉強をやりたいし、ゲームもしたい。カラオケも行きたい。最近体凝ってるから整体?マッサージ?も行きたい。あとは色々積読してるから読みたい。
  • 悩む。。。
  • 朝起きてカラオケ行こう!あとは服も買おう!昼からはかえってきてリフレッシュした気持ちでVueを勉強しよう!!!
    • 外で勉強できるようにノートパソコン買うべきか???
  • 来週はどうしようかな。。。取り合えず仕事がトラブル気味だから仕事に専念する。あとは朝は本読もう、夜はランニングかVueの勉強をする。
    • 平日の夜にリフレッシュできるアクションを用意したいな。ゲームはちょっと長いしカラオケも難しい、なにか無いかな。。。
  • あとは、Youtube見てる時間を減らそう。かえって来たらすぐYoutube、朝起きたらYoutube見たいな生活してるから改善していきたい。
    • TwitchのShakaさんが好きで、切り抜きとか公式チャンネルを見てると別の動画もついでに見ちゃうから。時間を浪費しないように好きなYoutuberとか、配信者のコンテンツをまとめて、そのコンテンツに集中できるアプリとか作ってみてもいいかも!

一言あったら

割といろいろとやってるかも?でも休日の過ごし方が割とこんな感じで変らないから外に出たりして満喫したぁ~って気分になりたい。3連休は3日目に新しいことをしようって気分になるからマジで良いなぁて感じ。明日は早起き(8時くらいだけど)する!全然一言じゃなくなったw

「Golangで行うポートスキャナ自作ではじめるペネトレーションテスト」を見た、ポートスキャンについて学んだ

zenn.dev

自作ってキーワードに惹かれて記事を見た、オライリーの書籍O'Reilly Japan - ポートスキャナ自作ではじめるペネトレーションテストについて紹介されており 書籍に出てくる自作ポートスキャナをGolangに書き換えてみたっていう内容のよう。まずもって、ポートスキャナって何?という状態。

用語から、サーバーに何のポートが空いているのか調べるためのツールかな?と思う。 steamのハッカーシミュレーションゲームで攻撃するときに何のポート空いてるか調べるツールがあった

Steam で 85% オフ:Hacknet

※85%OFFらしい(笑)(2023/11/10時点)

ポートスキャナ調べてみた

ポートスキャナとは - 意味をわかりやすく - IT用語辞典 e-Words

IT用語辞典によると、各ポートにアクセスし、応答があるかどうか・なんのソフトウェアが応答するかを調べて確認できるツールのよう。

ポートスキャンで開放ポートを知られないようにする手段

スキャンの種類

  • TCPスキャン
    • 一番一般的なスキャン方法、TCPコネクションの確立が成功すれば、ポートが開いていると判断する
  • SYNスキャン
    • TCPスキャンの一つ、SYNパケットを送信してサーバーがSYN/ACKまたはRSTどちらを返すかチェックする
    • SYNフラッド攻撃というものもあり、SYNパケットを大量に送信することでサーバーに負荷を掛ける攻撃
  • FINスキャン
    • TCPスキャンの一つ、FINフラグを立てたTCPパケットを送信してターゲットの応答を調べる手法
    • SYNフラッド攻撃と同じく、FINフラッド攻撃もある
  • ACKスキャン
    • ターゲットのポートがフィルタリングされているか確認するためのスキャン
    • TCPパケットのACKフラグだけを立てたパケットを送信することで確認する
  • UDPスキャン
    • UDPプロトコルを使用してポートをスキャンする手法
    • UDPを利用するDNSSNMPなどのサービスの存在を確認するために利用されることが多い
    • ほかにもファイアウォールのポリシーを確認するためにも利用される
    • TCPに比べてUDPの方がスキャンが完了するまで遅くなることがある模様

理解できていない用語/概念

終わりに

ネットワークも、サーバーもどう動いているのか把握しているつもりだったけど、ほとんど理解できていないことが分かった。 ポートスキャナの自作で学べること多そうだし、本買ってみようかな。。。 知らないことを調べるのは疲れるけど、面白い。

やりたいこと 2023-08

雑に今やりたいと感じていることをメモしておく

AtCoder

実装力、アルゴリズムの知識など実力不足を感じているのでAtCoderをやりたい

コーディングテストとかも十分にこたえられると感じていないのもある。

ISUCON

Webアプリケーションのサーバー構成やミドルウェアの設定、アプリケーションの負荷を考慮した実装などWeb開発の幅広い知識を学び、成長させることができるのでISUCONにチャレンジしたい

Next.jsをつかったフロントエンドアプリ開発

今主流のNext.jsをつかってアプリ開発の経験を積みたい、新規技術に触れていないので欲求不足もある

Goをつかったバックエンド開発

Next.jsと理由は同じ

基礎的な技術書を読む

テストコードや開発原則、設計原則など理解せずに実務に携わっているので体感したわけではないが、実力不足を感じているので知識を補うために技術書を読みたい。

気になるOSSのコードを読む

他人のコードを読むことでコードリーディングの力をつけ、コードの書き方や実装方法などを学ぶためにOSSのコードを読みたい。

Laravelの実装課題を見つけて解答する

自分の言語経験としてはPHPが多く、サーバーサイドで転職する場合はLaravelを利用したプロダクト開発が一番現実的なのでLaravelを使えるようになっておく。

【イベントレポート】B/43さんのTechTalk参加してきました~

こちらのB/43を運営しているスマートバンク / SmartBankさんのB/43プラスを担当されたエンジニアの方々のTechTalkに参加してきました!

b43.jp

株式会社スマートバンク | SmartBank, Inc.

最初に

SmartBankさん!TechTalkありがとうございました!! Fintech領域に触れるのが初めてだったので難しいところ多かったですが。 皆さんの雰囲気良くて楽しかったです!

お題目

  1. サブスクリプションサービスをつくる時にエンジニアが考えること
  2. クレジットカード発行システムの裏側
  3. ユーザー自由度の高い機能のためのテーブル継承戦略
  4. サブスクリプション機能制御の設計における勘所
  5. B/43プラスを作るエンジニア/PM/リサーチャー協業の裏側
  6. Q&A

サブスクリプションサービスをつくる時にエンジニアが考えること

学び

つくるものを決めるためには

  • ユーザーに理解しやすい一般的な使用を探る
    • 主要なプラットフォームのドキュメントを精読
    • 主要なプラットフォームのドメイン用語を整理
    • 自分たちのサービスでのドメイン用語を考えることで要求を洗い出せた
  • とりうる状態の遷移を洗い出す
    • ライフサイクルが重要
    • 状態を減らすことで複雑性を軽減
    • 状態遷移図を書き、要件による最小・最大の複雑性を比較

どうつくるか

  • 登場人物(エンティティ、イベント、リソース)を整理する
  • 参考になるドキュメントを参照し、リソースからデータ構造を整理
  • 永続化をするデータを取捨選択
  • 要件が満たせるかテーブル設計、ER図を確認
  • 上のイメトレをした後にコードを一気に書く

つくったものの検証

  • 日付・時刻に関するテスト
    • 有効期限を短縮したり状態を更新したりするツールを利用
      • App Store sandbox, Stripe Billing test clockを参考にした。
  • 状態遷移テスト
    • 状態遷移図から状態遷移表に整理していく
    • 状態遷移表からテストケースを書き起こす
    • 課金テストは中盤と後半で二回実施

クレジットカード発行システムの裏側

学び

  • カード情報を扱うにはPCI DSSを取得する必要がある
  • PCI DSSのスコープを小さくするためにシステムを切り出している
  • PCI DSSを適用しているサーバーには直接リクエストが飛ばせない
  • PCI DSSにより、本番ではログ(ファイル)が一切参照できないのでデバッグが少し大変

難しかったところ

  • PCI DSS
  • 生成鍵まわり
  • HSM

ユーザー自由度の高い機能のためのテーブル継承戦略

学び

単一テーブル継承

  • 一つのテーブルにプリセットもカスタムも入れる
  • 単一テーブルなので横断クエリが書きやすい
  • NULL 制約がかけられず、カラム数の肥大化が懸念される
  • migration 時の影響範囲が大きい

具象クラス継承

  • 全てのサブクラスをテーブルに分ける
  • 既存テーブルとの migration 処理が大変

クラステーブル継承

  • 継承フィールドのみをスーバークラステーブルが持つ
  • 固有フィールドはサブクラステーブルに
  • NOT NULL 制約問題の解消
  • 表現するのに実装力がいる。
  • Ruby では delegated_type を利用した
  • CTI ならではのイマイチなところ
    • カスタムカテゴリー登録日時を優先第一ソート、プリセットカテゴリの order を第 二ソートとして取得しなければならない

理解しきれていないところ

  • テーブル継承パターン
    • 単一テーブル継承
    • 具象クラス継承
    • クラステーブル継承

サブスクリプション機能制御の設計における勘所

学び

サブスクリプションの機能制御は大きく2パターン

  • サーバー側で機能制御の処理が完結するパターン
  • クライアントで制御が必要なパターン
    • 明細に画像を追加できる機能などは導線を断つことで表現している

B/43プラスにおける機能制御の設計

  • テーブル設計
    • プランごとに使用可能な機能の範囲を定義
      • 機能の使用に必要なプランをマスタ管理
  • アプリケーションロジック
    • B/43 プラスを利用可能な範囲は B/43 カードが起点
    • ロジックを段階的に分けて判定している
  • API 設計
  • クライアント側の状態管理設計
    • 不整合を発生させないことが一番重要
    • サブスクリプションの申し込み完了と同時にキャッシュを更新
    • DI コンテナのインスタンスのスコープ管理を用いてカード単位で適切に判定される ようにしている

難しかったところ

  • DI コンテナのインスタンスのスコープ管理
    • 頭の中でイメージできなかった。

Why, What, How をつくる部分

  • ユーザーアンケートとインタビューを行って機能に価値があるのか確認していた
  • 企画からリリースまでのスパンは1年、開発は 8~9 ヶ月
  • PRD に対してエンジニアが価値を出すには
    • 仕様としての一般調査した内容をプレゼンする
    • 仕様決定した際のリファレンスをログに残す
  • What に対する取り組み方
    • 機能の中にはファーストリリースに含めないようにしたものも発生した
    • 実装プランを提案することで、MVP に対する議論を促した
    • 機能の背景と価値がきちんと整理されていたので MVP の議論がしやすかった
      • 機能の背景と価値を共通認識がもてるように整理することが重要
  • PM として判断しやすかった点
    • MVP に含めるに際してオプションをエンジニアから提案してくれたので判断しやすか った。

B/43プラスチームへの印象

  • エンジニアとPM、UXリサーチャー + ユーザーで強く協力し合いながら仕事しているように感じた。
    • なにを、なぜ、どうやっての部分(PRD)
  • 開発だけでなく様々な業務に幅広く身を乗り出すエンジニアの方々ばかり

最後に

B/43プラスチームのTechTalkに参加して純粋に知見が広がったうえに 知見が広がったおかげで自分が理解できていないところがポロポロと出てきました。

TechTalkを開催してくださりありがとうございました!

LeetCode 5日目

LeetCode 5日目振り返りやっていきます。

36. Valid Sudoku

問題文

9×9の数独の盤面が有効かどうかを判定する。以下のルールに従って、塗りつぶされたセルだけを検証する必要がある:

各行には、1~9の数字が繰り返しなく含まれていること。 各列には1〜9の数字が重複なく含まれていなければならない。 3×3の9つのサブボックスは、それぞれ1~9の数字が重複なく含まれていなければならない。

注意してください:

数独の盤面が部分的に埋まっているものは、有効である可能性があるが、必ずしも解けるとは限らない。 埋められたセルだけが、前述のルールに従って検証される必要があります。

制約条件

  • board.length == 9
  • board[i].length == 9
  • board[i][j] is a digit 1-9 or '.'.

解答

function isValidSudoku(board: string[][]): boolean {
    const col = Array.from({ length: 9 }, () => new Set());
    const row = Array.from({ length: 9 }, () => new Set());
    const box =  Array.from({ length: 3 }, () =>
        Array.from({ length: 3 }, () => new Set())
    );

    for (let i = 0; i < 9; i++) {
        for (let j = 0; j < 9; j++) {
            const cell = board[i][j];

            if (cell === '.') {
                continue;
            }

            const x = Math.floor(i / 3);
            const y = Math.floor(j / 3);

            if (col[i].has(cell) || row[j].has(cell) || box[x][y].has(cell)) {
                return false;
            }
            col[i].add(cell);
            row[j].add(cell);
            box[x][y].add(cell);
        }
    }

    return true;
};

振り返り

ハッシュテーブルを使って3つの条件それぞれ9つの入れものを作って値をチェックする方法で実装しました。

3x3のサブボックスの配列の持ち方をどうするのか悩んだんですが。

自分は2次元配列の中にハッシュテーブルを格納する形で解きました。

ほかの人の解答を見ると別の方法で解いていたりするので面白いですね。

最初はハッシュテーブルの使い方があまり理解できていなかったですが。 直近は使い方がわかるようになってきていい感じです!

LeetCode 4日目

4日目の振り返りやっていきます!

今日は同僚と飲む予定なので朝のうちに。

347. Top K Frequent Elements

問題文

整数配列 nums と整数 k が与えられたとき、最も頻度の高い k 個の要素を返せ。答えはどのような順番で返してもよい。

制約条件

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104
  • kは[1, 配列のユニークな要素の数]の範囲にある。
  • 答えが一意であることが保証される。

解答

function topKFrequent(nums: number[], k: number): number[] {
    const frequent = new Map<number, number>();

    for (const num of nums) {
        if (frequent.has(num)) {
            frequent.set(num, frequent.get(num) + 1);
        } else {
            frequent.set(num, 1);
        }
    }

    // 出現回数で降順ソート
    const sorted = [...frequent.entries()].sort((a, b) => b[1] - a[1]);

    return [...sorted.keys()].slice(0, k);
}

振り返り

計算量はO(k + n logn) 処理速度もコードの見やすさも問題なさそう。

ただ、TypeScriptのMapを配列にして操作する方法がわからず解くのに1時間半はかかってしまった。

238. Product of Array Except Self

問題文

整数配列 nums が与えられたとき、answer[i] が nums[i] を除く nums のすべての要素の積と等しくなるような配列 answer を返す。

numsの任意の接頭語、接尾語の積は32ビット整数に収まることが保証される。

あなたは、O(n)時間で、除算演算を使わずに実行するアルゴリズムを書かなければならない。

制約条件

  • 2 <= nums.length <= 105
  • -30 <= nums[i] <= 30
  • numsの任意の接頭辞または接尾辞の積は,32ビット整数に収まることが保証される。

解答

function productExceptSelf(nums: number[]): number[] {
    const n = nums.length;
    const answer: number[] = Array(n).fill(1);

    let prefix = 1;
    for (let i = 1; i < n; i++) {
        prefix = prefix * nums[i - 1];
        answer[i] = prefix;
    }


    let postfix = 1;
    for (let i = n - 1; i >= 0; i--) {
        answer[i] = answer[i] * postfix;
        postfix = postfix * nums[i];
    }

    return answer
};

振り返り

この問題から1問あたりの時間制限を設けてチャレンジすることにしました。

早速、時間内に解くことができず解説にお世話になりました。。

問題の内容としてはnums[i]のnums[i - 1]までの積(接頭辞の積)とnums[i + 1]以降の(接尾語の積)を乗算するという問題

今思うと制約条件を正しく理解していれば自力で解くことができたのかも。 如何せん英語で問題が書かれており、理解できない場合は翻訳していたりするのだが見落としていることが多々ある。

LeetCode 3日目

3日目の復習やっていきます。

49. Group Anagrams

タイトルのまんまアナグラムになっている要素をグルーピングする問題

ひとまず自分のコード

function groupAnagrams(strs: string[]): string[][] {
    let answer: string[][] = new Array();
    let mapAnagram = new Map<string, number>();
    let count: number = 0;

    for (let i = 0; i < strs.length; i++) {
        const str: string = strs[i];
        const sorted: string = sortStr(str);

        let key = count;
        if (mapAnagram.has(sorted)) {
            key = mapAnagram.get(sorted);
            answer[key].push(str);
            continue;
        }

        answer[key] = new Array();
        answer[key].push(str);


        mapAnagram.set(sorted, key);
        count++;
    }

    return answer;
};

function sortStr(str: string): string {
    return [...str].sort().toString();
}

実行速度的には問題なし。ただ、処理が複雑になってしまった。

分かり易いコード

function groupAnagrams(strs: string[]): string[][] {
    const hash: Map<string, string[]> = new Map();
    
    for (const string of strs) {
        const sorted = string.split("").sort().join();
        if (hash.has(sorted)) {
            hash.get(sorted)!.push(string);
        } else {
            hash.set(sorted, [string]);
        }
    }

    return [...hash.values()];
}

無駄な宣言がなく、純粋に処理を読みやすい。 あと、Mapの値に答えで利用できる配列を格納しているので直感的にコードを理解できる。

フムフム直感的に理解できるコードか~

プログラミングの原則覚えないと。

実務で開発できてない分、家でプログラミングするのが楽しい!