【ISSUE】初めてのシステム案件で詰まったお話(Heroku + puppeteer)
2024年12月23日 22:38
こんにちは!ばーんです
今回は自分が初めて納品したシステム開発のお仕事で得たものを整理していきます。
今回書いていく内容は
について書いていきます。これからシステム開発していきたい!
と考えている方は、見ていただけると気づきがあるのかなと思います。
ざっくり大切だなと感じたことが3点。
①デバッグ / コードレビューはお金を支払ってでも現役エンジニアにお願いする
(デバッグは詰まりに詰まったか、単純に自分がしているところを見てもらう)
見ている観点がそもそも違うのでとても勉強になります。
②基礎を学ぶことが遠回りのように見えて近道
結局上辺だけの解決方法では解決しないことが殆どでした。
今回で言えば公式ドキュメントなどの一次情報を見る。linuxについて理解を深めるなど。
③簡単なことはGASで解決できる
システム開発これから携わりたい!という方はまずGAS触ればいいと思います。
クライアントの要望の多くは「スプレッドシート + GAS」で解決できました。
GASはできないことが明確なので、見積もりをたてる一つの基準になるかなと思いますし。
また、会社員の方であれば社内のルーチンなどは大抵GAS使えば効率化できます。
信頼を得るまでは時間外で学習としてやってみて完成させる。使ってもらって感触よければ信頼がついて業務時間中にできるようになります。
フレームワークは無し
実際にコードを書いて指摘を受けた部分、アドバイスされたこと、自分で感じたことを書いてます。
これができているようで出来ていなかったです。一番良いのは現役のエンジニアにデバッグしてもらうことかと思います。
できればその様子を横で見させてもらうこと(もしくは自分のデバッグ処理を横で見ててもらう)。
思考プロセスが全く違うなと感じました。
僕は起きた事象から「何が起きたか?」を推測して進めようとしてました。
(経験の浅い人はこうする傾向があると思います)
現役の方はエラーが出ているところから順番に確認していきました。
特にシステム開発であれば本番環境で動かすと思うのですが、ログが出力されるようになっていると思います。
(むしろなっていなければ、出すようにした方がいい)
これもエラーと全く同じです。まず、ログを見る。とても大事。
調べていったり要件を細かく分けていくと「あれ?これ意外といけんじゃね?」感がでます。
ネットに落ちてるコードちょっと変えれば…と思っていたらめっちゃ詰まります。
(例)Webページに遷移した後スクレイピングする処理
…etc
毎日こんな感じでしたToT
詰まったエラーで一番多かったのは、変数にデータを想定通りに渡せていないことでした。
それに気付かずロジックを書き換えたり…非常に無駄な時間を過ごしました。
console.log()
で泥臭く1つ1つの変数を確認していくとエラーの原因に行き当たることが多かったです。
基準は第三者が見た時に何をするのか分かるかどうか?
いろんな人にたくさん言われましたが中々習得できず…
他人のコードを積極的に見たり、コードレビューを重ねて受けるのがいいと思います。
記事を探すときは、大枠で
が多いと思うのですが、残念ながら記事に便利なものは余り多くはありませんでした。
なぜならシステム開発は応用的なものを作り上げていくので(基礎 + 基礎 = 応用)。
微妙に基礎から変更するにはそのメソッドが「何に対してどう動くのか」という仕組み部分を知る必要がある為に、公式にいってメソッドの処理を細かく見ないといけません。
こういうことできるかな?を探す
これはQiitaなどで書かれていることもありました。
ただ数回の検索ででてこない場合はロジックを考えてメソッドを組み合わせないとできないことが殆どでした。
エラーを直接打って対応方法を調べる
多くの人がぶつかったエラーでない場合は大抵でてきません。そして、自身とは関係ないことが殆ど。
エラーを読んで各メソッドがどういう処理をしているか把握する。変数に何が入っているか確認する。
基礎を把握することが一番の近道でした。
今回処理ごとに進めていって最後の段階でロジックが破綻していることに気付いたことがあります…
そんなことがあったり、メンターからのフィードバックも受け現在は処理の流れを先に書くようにしています。
これは現在書いているオセロゲームの処理ですが、このように日本語で記載していくことが大切だなーと学びました。
結果として時間が短縮できますし、今後必要な実装なども見えてくるので。
(上記のオセロゲームは書きかけのものです)
この記事なんかは見易かったのでおすすめです^^
http://labs.timedia.co.jp/2013/07/write-othello-in-javascript-with-functional-style.html
エラーとずっと対峙していると「あれ…?このエラーさっきも出会わなかったっけ?」
みたいな迷子状態が発生します。特に頭も動かしてるのでゴチャゴチャになってます。
都度メモをとること。何でもいいです。
こんな感じで大丈夫なので自分の思考をメモにとっておいて、自分のキャッシュを軽くすることが大切です。
「後で消そう〜」みたいな処理もその旨を記載する。
未来の自分が覚えているとは限らない。
便利なので「とりあえず今の処理はコピーしておいておいて…」は大抵使わない。
積もっていって大抵は醜いコードの塊ができるのでGitを使ってコメントはなるべく使わない。
また、コードの説明もできる限り避ける。
コメント書かなくても読めるようなコードを目指す。
簡単な成績表みたいなもので良いので、SQLでかけるようになっておく。
CRUD処理はできるようになっておく。
puppeteerの処理を実装していて詰まった内容を記載していきます。
これはpuppeteerに限らずですが、スクレイピングはサーバー攻撃になり得ます。
スクレイピングではないものの、過去学生の方が悪意なく書いたコードが無限に繰り返される処理で事件になったこともあります。
また、スクレイピングを利用規約にNGと明示しているサイトもあります。
(というか基本的に快くは受け入れられていないはず)
実装前は利用規約を確認すること。
スリープ処理を入れること。
ローカルで実装しているときはheadless: false
をオプションにつけて動かすととても見易いですが、本番環境(Heroku上)では使えません(ディスプレイがないので当然)
しかも、最悪なことにheadless: false
の状態だと動かないメソッドもあり、本番環境で苦労したことを覚えています…
早い段階でheadless: ture
で動かすことをお勧めします。
実例で言うと
この2つはheadless: false
で動きが変わるので注意が必要です。
おそらくgotoメソッドは不具合を抱えています。
https://stackoverflow.com/questions/62618052/how-to-get-puppeteer-to-simply-load-a-web-page
このStackOverflowにあるGitHubのIssuesも見ましたが、答えが出でてない。
症状としては、
議論の中では、CSS / JSのロードが終わっていないことも書かれていてそれが原因?
と書かれていましたが、CSS / JSのロードを無効にしても同じ症状。
また、質問者は解決したと書いていますが、そのURLへのgoto処理諦めているだけなので根本的には解決していない。gotoできなくなるURLに共通の特徴もない。
自分の場合は1,000件につき10件程度の処理落ちだったので、そのまま無視して実装しています。
(この辺はシステム要件によって対応が変わってきますが、自分の場合は無視しても問題なかったので)
自分は似たような案件がくれば次はseleniumで対応すると思います。
page.click
処理はheadless: false
では機能しません。
公式の中でChromiumのバグだ!って以前見たのですが見つけられずorz
ページを次のページに移動させる処理はURLのpage部分に変数を入れてforで回して解決しました。
こちらも意外な落とし穴だったのですが、headless: false
の状態はuserAgentに「headlessで動いてるで」っていう記載がされています。
そして、サイトによってはheadlessはアクセスを弾くサイトもあるのでご注意を。
その場合はuserAgentを変更するメソッドがあるのでそちらを使用してください。
これはとても使えました^^
(元記事があったのですが、見つからなかったので断念してます)
要素の取得は単数形と複数形があります。
取得するメソッドに応じて取得してくる内容もElementHandle
なのかNodeList
なのか変わってきます。
こういった細かい違いは探さないと出てこずハマりやすいのでご注意ください。
ちなみにpuppeteerで開発する際はこの2記事がとてもオススメです!
ここでわからなければ大抵公式にしか解答がなかったように思います。
https://qiita.com/taminif/items/1ba7f68aedd68bae5e09
https://qiita.com/go_sagawa/items/85f97deab7ccfdce53ea
記事に書いている要素の取得は、DOM取得→パース処理を流れで書いています。
DOMのツリー構造をそのまま保持して兄弟要素などを判定したい場合にそのまま流用してるとハマるのでご注意ください。
自分は一旦空の配列に入れて対応しました。
今回自分はn千件ほどの処理を同一ブラウザで処理していたのですが、puppeteerの仕様としてブラウザのキャッシュはずっと保持し続けるようです(というより解放されない)。
ブラウザをnewしたタイミングで作り直されるとのこと。
で、処理落ちを繰り返したので数件ほどでブラウザを立ち上げ直す処理を入れたら改善されました。
map + Promise.allで擬似的に並列処理を実装できます。
件数が多い処理を実装するときはおすすめです^^
Herokuで実行する時に詰まった部分です。
これが理解できていなかったので無茶苦茶詰まりました…
一番おすすめなのはheroku run bash
でbashを使用することができるので、
使用した後ls
やpwd
コマンドを打つと普段ターミナルで操作しているような感覚で操作できます。
後、デプロイされている内容を視覚的に確認できます。
自身は今回から「サーバーとは何か?」をもっと知っていかないとまずいと考えてlinuxの学習を始めました。
AWS / GCP共に無料でインスタンス生成までできるのでおすすめです^^
(両方公式ドキュメントも豊富ですし、記事も沢山あるので1人でもアプリをデプロイするぐらいまではいけると思います)
これは最初に明確にしていった方が良かったです…
今回の自分の件であればPostgreSQLは無料枠だと1万レコードが限界でした。
また、メモリの容量や稼働時間などクライアントが知りたがる範囲は事前に把握しておくべきでした。
当然ローカルとは環境が違うので、ビルドする時の障害があったり、ローカルでは動くけど本番で動かないメソッドなどもあります。
Heroku + puppeteerに関して言うと専用のビルドパックが必要です。
これは、過去不具合があったものを修正するために後から出されたのですが、タイミングによっては自分がひっかかることもあり得ます。
なので全部完成させてからではなく、ポイントポイントで確認すると手戻りも少なくなるのかなと思います。
納品後に**「ローカルでは動くけど、本番環境で想定通りの振る舞いをしない」**という自体が発生ToT
しかも、問題が何個か重なっているので改修にとても時間がかかりました(どうしようもなくなったので、最後は現役エンジニアの方にデバッグ手伝ってもらいました)
この時にDockerを使うと「環境が違うことが原因」or「そもそもコードに問題がある」という問題を切り分けられたので、楽に対応することができます。
herokuのような海外のサイトを使うとそこそこの頻度でクレジットカードの登録を求められます。
登録しておくとお金使わなくても使用できるものが変わるとか、そもそも登録しないとサービス使わせませんみたいなサービスもあるかと。
自分はそんなときはバンドルカードを使用しています。
https://vandle.jp/
クレジットカードのように使えますが、実態はプリペイドカードとして運用できるのでチャージ金額以上の支払いは無くせます。
(運用やプランによってはクレジットカードと同じ状態になるのでご注意ください)
年会費、登録費無料で身分証不要&即発行(アプリ)
便利なのでおすすめです^^
さいごまで見ていただいてありがとうございました!
今回で学んだことが非常に多くあったので、今後はそれらを消化しながら進んでいきたいと思います。
①デバッグ / コードレビューはお金を支払ってでも現役エンジニアにお願いする
②基礎を学ぶことが遠回りのように見えて近道
③簡単なことはGASで解決できる
一応結論をもう一回載せて締めにさせていただきます。ありがとうございましたm_ _m
[cv:issue_marketplace_engineer]
診断を受けるとあなたの現在の業務委託単価を算出します。今後副業やフリーランスで単価を交渉する際の参考になります。また次の単価レンジに到達するためのヒントも確認できます。