Torihaji's Growth Diary

Torihaji's Growth Diary

Little by little, no hurry.

LeetCode生活2日目

はじめに

まだまだ続く、2日目。

今日はむずいか簡単か。

ではレッツゴー。

Valid Anagram

2つの文字列s,tが与えられる。tがsのアナグラムである場合はtrue、そうでない場合はfalseを返せ

アナグラムとはある文字列を分解し、並び替えて別の意味の文字列を作るという言葉遊びのこと。

解法1

思いついたのはこのくらい。

文字列をsortして結果が同じであればok。

# @param {String} s
# @param {String} t
# @return {Boolean}
def is_anagram(s, t)
    s.split('').sort == t.split('').sort
end

ただ文字列を配列に分解するのはcharsがいいらしい。

可読性: chars は文字ごとに分割する意図が明確で、コードを読む人にとってわかりやすいです。
マルチバイト文字対応: chars はUTF-8などのマルチバイト文字にも正しく対応します。一方、split('') は場合によっては意図しない動作をする可能性があります。
最新のスタイル: Ruby 1.9以降、chars が推奨される方法となっており、今後のメンテナンスや他の開発者との共同作業でも一貫性があります。

知らんかった。

解法2

アルファベットの全文字の出現回数を調べることで同一か判断。

上の解法より早いそうだ。

def anagram?(s, t)
  return false if s.size != t.size

  ('a'..'z').all? { |char| s.count(char) == t.count(char) }
end

終わりに

まだ簡単な方だと思う。

昔こういう問題を解いていた時に比べて

手が動くようになってきたと思う。

継続あるのみ。頑張りたい。

LeetCode生活1日目

はじめに

これは プログラミングには数学必要ないと思っていた人間が

最近になって実務で扱った幅優先探索が全くわからんことに焦りを感じ

まずは簡単なアルゴリズムからやってみようという考えのもと

突然始まったものになります

  • 毎日必ず1問は解くこと。

  • 時間がある時に復習すること(このルールに対してはゆくゆく詰めていきたい)

進め方

neetcodeという leetcodeの問題ベスト100選!みたいなものをまとめたサイトがあるので

そのサイトを元に難易度が簡単なものからやっていく。

(neetcodeというのは 昔 neetだったサイト主がgoogleに入るためにleetcodeの問題を勉強し、

途中で得た知見をまとめた優良サイトのこと)

今回はrubyで進めていきたいが、neetcodeにはrubyがないので

neetcodeでやる問題をleetcodeで見つけて、それをやるというやり方にしていこうと思う。

考え方は自分が考えたやり方。わからないときはどうわからないかを記載して答えを見る。

挫折を防ぐために5分考えてもわからなかったら答えを見ようと思う。

Contains Duplicate

数字の配列numsが与えられている。重複要素があればtrue、なければfalseを返す。

考え方1

配列の要素を頭からloopを回して参照する。要素Aを取り出した後、その要素 + 1 ~ 末尾までに

要素Aが存在するかどうかで判定する

def contains_duplicate(nums)
  nums.each_with_index do |num, i|
    return true if nums.slice((i+1)..-1).include?(num)
  end
end

sliceは配列の要素を切り出して新しい配列を返してくれる。

include?は引数に与えた値が配列に存在するかを指定する。

考え方2

Setを使うやり方。Setは要素の順序は保証しないが、要素の重複は許さないもの。

これに対して値を追加し、判定に使用する

def contains_duplicate(nums)
    hashset = Set.new
    nums.each do |num|
        return true if hashset.include?(num)
        hashset.add(num)
    end
    false
end

考え方3

答え出して他の人のをみていたら見つけた。なるほどと思った

配列の要素数を調べ、その配列に対して重複を削除するuniqを適用した後の配列の要素数と比べることで

判断するというもの。

def contains_duplicate(nums)
  nums.count != nums.uniq.count
end

終わりに

まだやりたいという気持ちがあるが、1問やったので合格。

easyくらいなら続けられそうなので頑張りたい。

2つのeslintを追加しますた

はじめに

どうも torihaziです

課題のX_クローンを作っていて、2つの問題が多発および気になって仕方なくなったので

新しくlintのルールを追加しました。

問題

  • やば、またdebug用のconsole.log入れたままpushしちゃった
  • オブジェクトの分割代入時にkeyがごちゃごちゃなの気持ち悪い。

1つ目についてこれは新しくinstallせずともいけるらしい。

module.exports = {
  // 省略
  rules: {
    // 省略
    'no-console': 'error',
  },
};

これを使えば、"console.log だめ、絶対" になるらしい。

ただ、今思えばこっちにすれば良かったかもしれない。

module.exports = {
  // 省略
  rules: {
    // 省略
    'no-console': ['error', { allow: ['warn', 'error'] }]
  },
};

こうするとconsole.warnとconsole.errorは許しますということらしい。確かに。便利。

ただnpm run fixみたいなことしても修正されないから注意。

2つ目についてはinstallする必要あり。

eslint-plugin-sort-destructure-keys - npm

使い方はここに書いてある。

別にここまでやる必要なくね、という気もするが

気になってしまったので導入した。

おかげでその時の気分で描いてたものが統一されたので、よき。

尚且つ新しいことしれた優越感に浸れてなお良き。笑

終わりに

少し前までeslintについてないと必ず困るものでもないから毛嫌いしてたけど

使ってみるとあら便利だったので、これからも使っていきたい。

以上!!

Error: Objects are not valid as a React child (found: object with keys {~~~}). If you meant to render a collection of children, use an array instead.って何。

はじめに

やけに長いタイトルですね。

よくあるReactのエラーです。

ネットで調べたらすぐ出てくるかと思いますが。

わざわざ記事にしなくてもいいかもと今になって思います。

結論

「あんた、Objectをレンダーしようとしてるけど、できまへんで。」

ということ。

よくあるのはerrorをそのまま 描画しようとして、実はそのエラーがただの文字列ではなくてオブジェクトで、というオチ。

error.messageとかにすれば OKになるやつです。

誰しもよくやることなので気をつけましょう。

Next.jsの環境変数は本当にprefixをつけるかつけないかで参照範囲が変わるのか

はじめに

公式が言っていることを検証してみようの会です。

Basic Features: 環境変数 | Next.js

検証

pages router、typescriptで Next.jsのアプリを作成してあること前提で行います。

pages配下に下記を記載

pages/hoge.tsx

export default function Hoge() {
  return (
    <div>
      <p>PRIVATE_EXAMPLE: {process.env.PRIVATE_EXAMPLE || "not found"}</p>
      <p>NEXT_PUBLIC_EXAMPLE: {process.env.NEXT_PUBLIC_EXAMPLE}</p>
    </div>
  );
}

pages/api/hoge.ts

import type { NextApiRequest, NextApiResponse } from "next";

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  res.status(200).json({
    message: process.env.PRIVATE_EXAMPLE,
    nextPublicMessage: process.env.NEXT_PUBLIC_EXAMPLE,
  });
}

env

PRIVATE_EXAMPLE=PRIVATE_INFO
NEXT_PUBLIC_EXAMPLE=NEXT_PUBLIC_INFO

pages routerでは それぞれ /hogeと /api/hogeとしてアクセス可能であるのでみてみると

/hoge

/api/hoge

以上です。

終わりに

公式の言う通りでした。疑ってすいませんでした。

2025年1月の振り返り(実務 6ヶ月目)

はじめに

みなさん、おはようございます、torihaziです

本日は1月最終週間近ということで いつも通り月の振り返り記事を書いていこうと思います

早いところもうすでに2025年の1 /12が終わろうとしています。

常に何ができるかできるようになったのか、できないのかということを

常に書き残していっていつかの自分が楽になれるように頑張ります。

あとは「めっちゃできるようになってるやん」という自己満足のためでもあります。

ではいきましょうか。

感想

1月はそうですね。

実務も大変だったし、年初からイベントもあるしで

慌ただしかったかと思います。

実務の方はActionCableを使ったWebSocket通信を実装しましたが、

「なんかできちゃった、作れちゃった」という感じでまだ腹落ちできていないところが多々あります。

イベントについては クラウドプラチカというものに関するものでこれもまた量が凄まじかったです。

初めてのインフラタスクも無事終えて、なんとなくインフラに手を出し始めた月でもありました。

一時は フロントではなくバックエンド + インフラを専門にしていくんだとなっていましたが、

最近は フロントも楽しいなと思い始めてきました。

見た目がすぐに反映されることに対しては別にそこまで面白みを感じておらず、

どちらかというとそれ以外のことに対して興味があります。

ESLintやPrettierを使ってどれだけオリジナルの 規約を作れるか、自動保存で走らせるようにするのか、

はたまた git commit 使った時に走らせるようにするのかだったり、

最近やった フロントエンドから バックエンドを経由せず AWSのS3に PresignedURLを通じたファイルアップロードであったり。

TypeScriptもまだまだ全然できること多いんやなと。

新しい視点を取り入れて、最近は技術の上達を感じています。

ということでマインド面および技術の棚卸しに移ろうかと思います。

マインド面

質問の数をこなすようにした

なぜかというと自身の抱えている課題をすぐに解決するためです。

そしてすぐに解決するためには「どこまでがわかってここからがわからない」というように

自身の不明点を適切に言語化し、有識者に聞くことが必要です。

適切に言語化できればそれは AIに投げることもできます。

そして言語化する際は可能な限り、「〜な感じ」であったり話し言葉にならないように気をつけます。

対面であればそうした言語外のものも身振り手振りで伝えられるかもしれませんが、

今後非対面でテキストで仕事を進めるのであれば曖昧な表現は回答者に負担を強いることになります。

で冒頭の、なぜ質ではないかというと

量をこなせば自然と質も上がるからです。(勤務先の社長に聞きました笑)

最初は難しいです。ただ意識していくとエラー解決も早くなります。

以下に私がよくやっている考え方を掲示します。ご参考までに

  1. まずは何ができれば嬉しいのか、当初の目的は何かを書き起こす(一番大事です)
  2. そこから段階を分けて1を達成するためには〇〇、それを達成するには〇〇と記載する。ここでは原則1つの事象のみに触れてください。詰め込みすぎると訳がわからなくなります。
  3. 2を積み重ねていくと自分が所有している知識と行いたい実装方法が乖離してくる場面が出てくるのでそれを詳しく言語化します。(例えば今の知識だとこう書けるもしくはこうなるはずなのに、それではできなそうということがわかった等)
  4. 3で記載したことを他者に伝える。

これを続ければエラー解決に伴い、自身の知識も向上します。

当たり前かもしれませんが、最近わからないところがわからないと感じる場面が増えてきまして。

これを続けてたらそう感じる場面が減ってきました。

3の場面で「今の知識だとこう書くと思ってた」 => 「調べたらこういう書き方やり方もあった」という発見にも繋がりますし、

そもそも今の知識が誤っていることに気づけ、深い理解にもつながります。

最初はつまらないかと思いますが、慣れてくればゲームみたいで楽しいです。

他者をよく頼るようにした

これは去年から続けていますが、今年はより一層心掛けています。

なぜかというと新しい視点を取り入れられるから、神社のおみくじでそうしろと書いてあったから笑

他力本願マンというわけではありません。

他者に頼ることで新しい知識を取り入れられることはもちろん、

頼る上で上記の質問に関する要件も満たせるので万々歳というだけです。

疑問を多く持つ

開発を半年間続けていくと、「時間もないしこう書いてあるからこうしよう」というように

基礎をおざなりにして慣習に従って書いている自分が時々います。

最近は意識するようにして、「なぜこれを書くのか」、「これをするにはこの手法が適切だからこれを書こう」

というように舵を切り替えるようにしています。

そのおかげで今まで「わかる」と思っていたことが実はそうでもなかったりしたことがわかり

深い知識を得ることができました。

ということでこのくらいで技術面の棚卸しに入ります。

フロントエンド

触ることが多かったのでかけることが増えておいてほしいです。

ESLintについて

コードに一定以上の秩序をもたらし、コードの品質向上に一役買ってくれるツールです。

Tailwindcss のクラス名が適切に並べ替えられているかとか使ってないimport文をエラー表記したりとか。

特にクラス名並び替えてなんの意味があるかと言えば、読みやすいからです。

flex 設定してから flex-col指定して云々やるのであれば あー縦にしたいのかとわかりますが、

flexとかいて その間にあれやこれややって、終わりくらいに flex-col設定していたら

ぱっと見わかりにくいですよね。

Automatic Class Sorting with Prettier - Tailwind CSS

調べたら色々載ってるのでぜひやってみてください。

ちなみにこの知識はHCのCTOに頼ることで得た知識です。

最初は defaultの extends: ["next/core-web-vitals"]しかありませんでしたが、

今はこんな感じです。まだ導入して嬉しいことが増えたかは微妙ですが、

コードが「なんか綺麗に整ってる」ので優越感に浸ってます😆

{
  "extends": [
    "next/core-web-vitals",
    "plugin:tailwindcss/recommended",
    "plugin:jsx-a11y/recommended",
    "plugin:import/recommended"
  ],
  "plugins": ["unused-imports", "tailwindcss", "jsx-a11y", "import"],
  "rules": {
    "unused-imports/no-unused-imports": "error",
    "tailwindcss/classnames-order": "error",
    "eol-last": ["error", "always"],
    "jsx-a11y/aria-props": "error",
    "jsx-a11y/aria-proptypes": "error",
    "jsx-a11y/aria-unsupported-elements": "error",
    "import/order": [
      "warn",
      {
        "groups": [
          "builtin",
          "external",
          "internal",
          "parent",
          "sibling",
          "index",
          "object",
          "type"
        ],
        "newlines-between": "always", // import groups の間 1行あける
        "pathGroupsExcludedImportTypes": ["builtin"],
        "alphabetize": { "order": "asc", "caseInsensitive": true }, // 大文字小文字関係なくアルファベット順にしたい
        "pathGroups": [
          { "pattern": "type/**", "group": "internal", "position": "before" },
          {
            "pattern": "features/**",
            "group": "internal",
            "position": "before"
          },
          {
            "pattern": "components/**",
            "group": "internal",
            "position": "before"
          },
          { "pattern": "lib/**", "group": "internal", "position": "before" }
        ]
      }
    ]
  }
}

Next.jsのenvファイルには記載方法が2つある

これ、最近まで知りませんでした。

NEXT_PUBLICというprefixをつけるかつけないかです。

前者は クライアント側およびサーバ側から参照が可能ですが、後者はサーバ側からのみ参照が可能です。

今までNext.jsで環境変数を扱うならprefixつけるべし、という頭でやっていたので発見でした。

事の発端としてはフロントエンドにおいて扱う認証情報をどこに書けば良いのかと疑問に思った時でした

後に記載する PresignedURLを介したS3へのファイルアップロードを実装する際、

クライアント定義時にあらかじめ設定したIAMuserの ACCESSKEYなどを記載する必要がありました。

直書きはもってのほかで、かといってprefixをつけたら漏洩の恐れがありますとAIに言われて途方に暮れていたところ

サーバ側でのみ参照可能なprefixをつけずに定義する方法がありますよとAIに教えてもらい調べてみると確かに公式にありました。

Basic Features: 環境変数 | Next.js

これも本当にできないのかあとで記事にしたいと思います。

PresignedURLを介して S3にファイルを直接upload

これは別で記事にする予定なので詳しくは書きませんが、やりたいと思ったきっかけは

実務でbackendを介したs3uploadをしているのでそれをやろうとしたらHCのCTOから

フロントからもできるでと言われたからです(これも頼りの効果です笑)

おかげでS3のURLの仕組みやsdkの知識も増えて万々歳です。

APIRoutesという選択肢

これについてはまだ深掘りが必要ですが、フロントエンド側でサーバ側の定義ができるとのことです。

上のPresignedURL実装にあたり、クライアントに露出させずに認証情報を取得しそれを扱うといった処理周りを

記載する場所として適切だそうです。

パッと思いつくのがここら辺なので次Backend側です。

バックエンド

devise、token-authってなんもせんでもいけるんや

何もしないは誇張です。

今までdeviseって「設定が多くて面倒」であまり公式ドキュメント読まず(読んでいたがわかっていなかった)に

やっていましたが読み返してみるとEメール認証であれば特に何も書かずにいけるんだということがわかりました。

1,2回目の時に作ったXクローンのバックエンドとか悲惨ですね、多分。

例えばEメール認証の登録および確認メール、ログインについては

  • コントローラについて application_controller.rbに2行書くだけ
  • config/deviseなんとか.rbに書く
  • application.rbにセッション関連のものを使えるように useで記載
  • routes.rbに記載

くらいでいけます。

今まで qiitaとかでよくあるみたいな rails g controllerしてコントローラ作りましょうとか

そういうのしないでもいけます。

確認メールを誰から飛ばすのか、そのurlをクリックしたらどこに飛ばすのか

今まで強引にcontrollerに記載してましたが、後者に至ってはdevise-token-auth.rbの最後に

config.default_confirm_success_url = 'http://localhost:3000/auth' みたいにしてれば勝手に遷移します。

もちろんフロントから認証情報postする際に confirm_success_urを一緒にpostするやり方もありますが別にしなくていいでしょう。

兎にも角にも「公式をよく読め」とわからされました。

英語ですけど英語の勉強にもなるしね。

corsについて

辞書的な説明だと"オリジン間のリソース共有の仕組み"を扱っているものです。

セキュリティ機能の一種で異なるオリジンからの情報、送る情報を受け渡す際に活躍します。

そもそもオリジンとはなんぞやというと、"スキーム名 + ホスト名 + ポート番号"から成り立つもので

よくある例だと http://localhost:8000

スキーム名が httpで、ホスト名がblog.hatena.ne.jp、ポート番号が8000です。

オリジンが異なるというのは

ということです。遭遇する場面は フロントエンドとバックエンドを別で開発している時だと思います。

バックエンドはAPIサーバとして、フロントエンドはAPIを叩いてその情報を元にviewとして機能するだけという構成です。

歴史的な経緯に対する理解はまだ浅いですが、昨今のサーバ機能の向上に伴うバックエンドフロントエンド分離に起因していると思います。

ざっくりいうならば知っている人以外しかやり取りしない仕組みです。

オリジン間リソース共有 (CORS) - HTTP | MDN

Railsでは rack-corsというgemを入れて cors.rbに設定する必要があります。

いくつか記載する項目があります。

  • origins : 誰から(フロントエンド)の通信を許可するか
  • resource: 自分のどのファイルに対する通信を許可するか
  • headers: フロントエンドからのリクエストヘッダに何を許可するか
  • expose: サーバからのレスポンスヘッダでクライアント側に何が見えるように許可するか
  • methods: どのHTTPメソッドを許可するか

を指定します。 Railsに nginxを使用しているなら nginxにも追加で設定が必要です。

Railsのメソッドは3行くらいから積極的に別メソッドに切り分けるべし

ベストプラクティスかどうかは知りませんが、そうしないとrubocopに怒られるので。

Rails特有の戻り値の書き方になれるために、責務分離するためにも意識していこうと思います。

RailsのDBのカラムを表示させるときに "FILTERED"となる原因

記事書きました。

config/initilizers/filter_parameter_logging.rbの下記が原因です

Rails.application.config.filter_parameters += %i[
  passw secret token _key crypt salt certificate otp ssn
]

つまりカラム名に上の文字列を含むものは FILTEREDと表示されます。

外せば見えるようになりますがデフォルトのセキュリティ機能なので自己責任で。

。。。。

くらいですかね、パッと思いつくのは。

ないよりマシなのでまあいいでしょう。

インフラ

ついにこの項目が少し書けるようになってきました。

S3のPresignedURL発行のためにs3自体にcorsを設定する必要がある。

これは後で記事書くので項目名だけで。

作成したIAMユーザに対しては必ずMFA設定しましょう

技術顧問曰く、サービス開発が頓挫する原因の一つにPW当てられることによるサービス乗っ取りがあります。

秒で設定できるので必ずやりましょう。

おかげでMFA設定方法についてはマスターしました笑

aws configureというコマンドは "--profile 名称"とすることで切り替えられる

そもそもaws configureというコマンドは aws cliを使う際に使用する認証情報を設定するためのコマンドです。

aws configureと入力すると 作成したIAMuserの access key , secret access key , region等を記載する必要があります。

そしてそれは defaultで使用される情報となります。

もし異なるuserとして設定したい場合は aws configure --profile admin(任意の文字列)とすればokです

使用する際も --profile admin みたいにすれば cliからデフォルトとは違うuserとしてアクセスすることが可能です。

。。。

あとはバケットの作り方、IAMuserの作り方くらいですかね。

去年に比べてインフラにも足を踏み入れることができたので成長です。

S3のpresigned URLという手法をやる上で身についていったものが多いので CTOに感謝です。

終わりに

以上で 実務半年の振り返り記事を終わろうかと思います。

みなさんもどんどん人に頼ってみてください。

新しい発見がありますよ。

あとそうそう。

よくある職務経歴サービスで触れられる ESLintという項目にチェックが入れられるようになりました

嬉しいです。

ということで他の技術記事作成に取り掛かります。

では。

Railsのbuildとかcreate!の引数に文字列は渡してはいけません。

はじめに

しっかり理解してればつまらないこと。

これを機に理解しました。

前にもやったことがあったのでエラー文見てピンときました。

戒めのためです。

現場

tweet = current_api_v1_user.tweets.create!(tweet_params[:content])

と書いたら

#<ArgumentError: When assigning attributes, you must pass a hash as an argument, String passed.>

と言われました。

hashを渡してね、文字列渡しているよ

ということ。

解決

 tweet = current_api_v1_user.tweets.create!(content: tweet_params[:content])

createに渡す引数をhashにしましょう。

以上です。

終わりに

このエラー文見るの2回目だったのですぐ気づきました。