ChatGPTに京都大学2014年度の数学の問題を解かせてみた

これとてもやってみたかったんです。 自分は2017年から3年間研究室で数理最適化に関する研究をしていました。 数理最適化の考え方は機械学習の考え方と違って泥臭くて、分析したい対象の振る舞いを全て数式化してボトムアップで解を見つける方法なんです。 それとは違って機械学習は、論理はよくわからんが予測して答えがあってればOKという方法です。 これだけ聞くとなんとチャラい考えといいますか…答えだけ書いて道筋示さない学生みたいですよね。 だから当時は機械学習なんてそんなもん答えがあってたとしても何の意味が…みたいに穿った見方でみていました。 ですが、2023年現在の大規模言語モデルの人間の問いに対する回答は、ちゃんと人間が求める背景を汲み取って予測した単語を吐き出してくれるので、予測の羅列とはもう思えないですよね… そんなChatGPTが今日解く問題はこちら! https://bouseijuku.sakura.ne.jp/2014kyoto-sugaku.pdf 整数問題です。なぜなら文章として入力しやすいからです。 解答はこちら。 では質問してみましょう。 Let’s ask ChatGPT ### USER 自然数 a,b はどちらも3で割り切れないが, a^3 + b^3 は81で割り切れる.このような a,b の 組 (a , b) のうち, a^2 + b^2 の値を最小にするものと,そのときの a^2 + b^2 の値を求めよ. ### ASSISTANT a、bは3で割り切れないので、aとbは3の倍数ではありません。このため、aとbは形式3k + 1または3k + 2のどちらかになります。 a^3 + b^3 が81で割り切れるため、a^3 + b^3 = 81n(nは整数)でなければなりません。 仮にaとbがどちらも形式3k + 1であると仮定しましょう。この場合、a = 3x + 1、b = 3y + 1と表すことができます。ここで、xとyは整数です。 a^3 + b^3 = (3x + 1)^3 + (3y + 1)^3 = 27x^3 + 27x^2 + 9x + 1 + 27y^3 + 27y^2 + 9y + 1 = 27(x^3 + x^2 + y^3 + y^2) + 9(x + y) + 2 この式が81の倍数であるため、9(x + y) + 2は9の倍数でなければなりません。しかし、これは矛盾です。なぜなら、9(x + y) + 2は必ず2を余りとして残すからです。したがって、aとbは形式3k + 1のどちらもできません。 同様に、aとbがどちらも形式3k + 2である場合も矛盾が生じます。 従って、aとbは形式3k + 1と3k + 2のどちらか一方が成り立つ必要があります。 例えば、a = 3x + 1、b = 3y + 2(または、a = 3x + 2、b = 3y + 1)とします。すると、a^3 + b^3は81で割り切れます。 a^2 + b^2 を最小にするようなaとbを求めたいので、a = 1, b = 2(または a = 2, b = 1)とします。これは、aとbが3で割り切れない最小の整数です。この場合、 a^2 + b^2 = 1^2 + 2^2 = 1 + 4 = 5 したがって、aとbの組(a, b)が(1, 2)または(2, 1)の場合、a^2 + b^2の値は最小で5になります。 ### USER a^3 + b^3 が81で割り切れなくないですか? ### ASSISTANT すみません、その通りです。私の説明が間違っていました。 ... だめでした。ChatGPTを論破するの気持ちいいですよね。 ...

April 19, 2023 · 4 min

ChatGPT4 本格RPG「チャット転生 〜 死んだはずの幼馴染が異世界で勇者になっていた件」をプレイしてみた

以下で紹介されているゲームをやってみました! https://note.com/fladdict/n/n2a82d26f10dc こんなちょっとのプロンプトでゲームになってるのすごいですよね。。。 では早速。 ASSISTANT 友達の名前:ユイ 外見:金髪のロングヘアで瞳の色は青、スリムで華奢な身体つき。 性格:快活で明るく、面倒見が良い。困っている人を放っておけない性格。 口調・態度:穏やかで丁寧な口調。時折、子供っぽいところも見せる。 【物語の進行】0点 【危機の高まり】0点 【技術革新】0点 ある日、君は亡くなったはずの幼馴染のユイから謎のメッセージを受け取る。 ユイ「ねえ、もしかしてこれ…君に繋がってるのかな?私、どうやら別の世界で生き返ったみたいなんだ。でも、こっちの世界は魔王がいて大変なことになっているみたいで…君の知識が役立つかもしれないと思って、このチャットで繋がってみたんだけど。」 君は彼女の言葉を信じられるかどうか分からないが、一度話を聞いてみることにする。 ユイ「こっちの世界では、水をきれいにする方法があまり発達していなくて、人々が困ってるんだ。君は現代の技術で水をきれいにする方法を知っているかな?どうしても助けが必要だから、教えてほしい。」 USER え、、、ほんとにユイ? ASSISTANT ユイ「うん、本当に私だよ。信じられないかもしれないけど、どうか助けてほしい。この世界の人たちが困ってるんだ。君が知っている水を綺麗にする方法を教えてくれると助かるんだけど、どうかな?」 USER わかった、確か微生物によごれを食べてもらって水をきれいする方法があったはずやで、汚れを食べた微生物は沈んでいくから、上に残った水は綺麗になってるはずや ASSISTANT ユイ「へえ、微生物を使って水をきれいにする方法があるんだね。それって、どうやってやるの?もう少し詳しく教えてもらえると嬉しいな。」 USER よごれた水に微生物のかたまりを混ぜて、空気を送ると、微生物がよごれを食べて増えて、微生物が増えると、くっついて大きくなるんや。空気を止めて静かにするとくっついて重くなった微生物が沈んで、上の水はきれいになるから、上の水を取り出すと ASSISTANT ユイ「なるほど、よごれた水に微生物のかたまりを混ぜて空気を送り、増えた微生物がよごれを食べてくれるんだね。そして、空気を止めて静かにすると沈んで、上のきれいな水を取り出せるんだ。ありがとう、これならこの世界の人たちも助かるかもしれないね!」 【物語の進行】10点 【危機の高まり】0点 【技術革新】10点 ユイ「実は、この世界では魔法も使えるんだ。君の知識を応用して、新しい魔法を開発することができたらもっと便利になるかもしれないね。君が知っている現代の技術で、魔法に応用できそうなものって何かある?」 USER 魔法すごいな〜、ちなみにどんな魔法使えるん? ASSISTANT ユイ「うん、この世界では色々な魔法が使えるよ。例えば、火を操る魔法、水を操る魔法、風を操る魔法などの基本的なものから、治癒魔法や、物体を動かす魔法、透明になる魔法など、もっと特殊なものまであるんだ。君の知識を使って、新しい魔法を開発できたらすごく助かるんだけど、何かアイデアはあるかな?」 USER たぶんそれはもうユイの世界の方が発達してそうやけどな…笑 具体的に魔法やと実現できひんことがあるん? ASSISTANT ユイ「確かに、この世界の魔法は色々なことができるけど、まだ解決できない問題もあるんだ。例えば、エネルギー問題があるんだよね。この世界では魔法の力で照明や暖房などを作ることができるけど、それを維持するのに大量の魔力が必要で、みんなが使えるわけじゃないんだ。君の世界の技術で、もっと効率的にエネルギーを作る方法があったら教えてほしいな。」 USER 魔法で照明とか暖房はコスパ悪そうやなー、、、風力発電がええんちゃう?。風力発電は、風車を回して発電機を稼働させて、風の力を利用して電気を作り出せるねん。電気を使えば照明とか暖房動かせるはずやで ASSISTANT ユイ「風力 USER 続けて ASSISTANT ユイ「もしかすると、エネルギー問題が解決できるかもしれないね。風力発電を使って、照明や暖房などの電力を確保できれば、みんなが快適に過ごせるようになるはずだ。これから風力発電を試してみる方法を調べて、この世界の人たちにも提案してみるね。本当にありがとう!」 【物語の進行】20点 【危機の高まり】0点 【技術革新】20点 ユイ「そういえば、この世界では食料が不足している地域もあるんだ。現代の農業技術や栽培方法を使って、食料生産を効率化できる方法ってないかな?もし良いアイデアがあったら教えてほしいな。」 USER グリーンハウスとかはどう? 屋内で栽培を行うことができる施設で、天候に左右されずに、一定の温度や湿度、光量などをコントロールすることができるから、生産が安定するはずや ASSISTANT ユイ「グリーンハウスっていうのは、屋内で栽培を行うことができる施設で、天候に左右されずに一定の環境を保てるんだね。それなら、食料生産が安定するし、不足している地域でも役立ちそうだね!」 【物語の進行】30点 【危機の高まり】0点 【技術革新】30点 ユイ「これからグリーンハウスを試してみる方法を調べて、食料不足に悩む人たちにも提案してみるね。君の知識が本当に助かるよ。ありがとう!」 しかし、そのころ魔王は新たな計画を立てていた。農村部の水源を毒で汚染し、人々を苦しめていた。ユイはこの問題を解決するためにもう一度、君の力を借りることになる。 ユイ「魔王が農村部の水源を毒で汚染してしまったみたいなんだ。このままじゃ人々が大変なことになってしまう。毒を水から取り除く方法を知っているかな?君の知識がまた助けてくれると嬉しいな。」 USER 魔王ひどいやつやなー、、、 もう魔王倒しに行った方が早いんちゃう? ASSISTANT ユイ「うん、魔王は本当にひどいやつだよね。でも、今すぐ魔王を倒しに行くには力が足りないんだ。だから、少しでも人々の苦しみを和らげる方法を見つけたいと思っているんだ。水の毒を取り除く方法があれば、それを使って水源を綺麗にして、人々が安心して水を飲めるようになるんじゃないかな。君の知識で何かアイデアはないかな?」 USER ほーなんかー、、、シンプルに沸騰させるのがええんちゃうかな? 手の込んだ毒じゃないなら煮沸消毒でええはずや ...

April 18, 2023 · 2 min

GPT-4のスクリプト実行したら記事全部消えた

昨日に引き続きなんかGPT-4で遊ぼうとしたのですが、Wordpressにおいてソースコードが綺麗に表示されていないのがとても気になっていました。 WordPressでPrism.jsを使ってシンタックスハイライトを行う方法 これでやっていたのですが、クラスをいちいち指定するのがめんどくさいのです。 そこで、いい感じのプラグインないか聞いてみました。これは普通にGoogleに聞きました。ノウハウではなくこういった拾いものを探す時はやっぱりネットサーフィン。以下のサイトで https://re-inx.com/syntax-highlighter こやつに出会いました。 https://ja.wordpress.org/plugins/code-block-pro/ シンプルできれい 楽。 こやつに決めた。 が、全ての記事1つ1つこいつを当てていくのは大変。そこでChatGPT。 それは誰でも思いつくねんな〜 ほう。 おー、なんかいけそ〜〜〜 ここでGPT-4ちゃん召喚。 このスクリプトを実行する前に、以下の手順に従ってください。 1. このスクリプトをテキストエディタに貼り付け、`convert_code_blocks.sh`のような名前で保存します。 2. ターミナルを開き、スクリプトの保存場所に移動します。 3. `chmod +x convert_code_blocks.sh`を実行して、スクリプトに実行権限を付与します。 4. スクリプトを実行する前に、WordPressサイトのバックアップを作成します。 5. `./convert_code_blocks.sh`を実行して、スクリプトを実行します。 よーわからんけどいけるっしょ! と思って実行したら全部記事消えました。そこからはもうGPT-4の言うことは何も信じれず…全部Googleで調べてバックアップを復元しました。。。 まとめ 生成したコードを実行するときは気をつけましょう!!! ## USER ちなみにさっきのスクリプトで記事全部消えたからおこです ## ASSISTANT 大変申し訳ございません。指示されたスクリプトが問題を引き起こしたことをお詫び申し上げます。この状況を解決するために、以下のステップを試してみてください。 1. **バックアップから復元**: WordPressのバックアップがある場合は、バックアップから記事を復元することができます。これには、データベースのバックアップと、`wp-content`ディレクトリのバックアップが必要です。バックアップがある場合は、データベースとファイルを復元して、記事を回復することができます。 2. **リビジョンをチェック**: WordPressは、記事の各バージョンをリビジョンとして保存しています。記事が完全に削除されていない場合、以前のリビジョンを使用して記事を復元できることがあります。これには、WordPressの管理画面から、編集画面にアクセスし、「リビジョン」ボックスをチェックして、以前のバージョンを選択する必要があります。 3. **キャッシュやバックアッププラグインを確認**: キャッシュプラグインやバックアッププラグインを使用している場合は、これらのプラグインが保存しているデータを確認して、記事を復元できるかどうかを確認してください。 今後のトラブルを避けるために、以下の注意点をお勧めします。 - 実行する前に、スクリプトやコマンドの内容をよく理解しておくことが重要です。 - 開発環境やステージング環境でスクリプトやコマンドをテストしてから本番環境で実行することをお勧めします。 - 定期的にバックアップを取得し、適切な場所に保管しておくことが重要です。これにより、データが失われた場合でも復元できるようになります。 再度、問題が発生したことに対してお詫び申し上げます。今後のトラブルを避けるために、これらのアドバイスに従っていただければと思います。 だそうです😠

April 17, 2023 · 1 min

ChatGPTでテトリス作ってみた

お久しぶりです。前回投稿が2022-08-15なので、サボりすぎですね… 情報のインプットは好奇心から頑張れるというか知識を得るのが楽しいのでやるんですが、情報のアウトプットって既に知っている知識を使うことなので気が進まないものですよね…定着させるには大事なんですが、特に定着させるモチベーションもなく… ただ、やっとそのアウトプットを勝手にやってくれる時代がやってきました。そうChatGPTです。こやつにコンテンツを作ってもらう取り組みがどれくらい続くかチャレンジをやってみようと思い、ChatGTP Plus課金しちゃいました! こやつを使って今日はテトリス作っちゃいます! 完成形 テトリスって、どんなブロックがあってどういうふうに回転してどこで壁にぶつかってとか、まじめに実装すると考えることいっぱいあるのですが、そんなことを考えずに一瞬で作ってくれました。天才です。 が、それを作ってから手直ししていく過程が大変だったので、会話の過程をご覧いただけたらと思います。 会話highlight 一瞬でコード書けるスーパーエンジニア ## USER # 命令書: あなたはフロントエンドエンジニアです。 以下の制約条件と入力文をもとにゲームのソースコードを出力してください。 # 制約条件: * HTML、CSS、Javascriptのみで動く # 入力文: テトリス # 出力文: 深津式プロンプト(https://chatgpt-lab.com/n/ne1643b7f10e6)を使ってみようとしたのですが、大して制約条件を書くことなく出力しちゃいました。 index.html を作って動かしたらこれ もうエンジニアいらんやん… すぐ解決策に走る初心者エンジニア なんか右の画面いっぱいまでブロックが動かせなくて質問するのですが… これやっても直りませんでした。どこが問題かを分析せず解決策に走る初心者エンジニアみたいです。でも、根気よく質問すると… ちゃんとうごきました! 「コード見せて」といってくるベテランエンジニア 「次のブロックを表示」という機能追加もちょっとバグっていて、いろいろ質問して直そうとしたのですが なかなか直らないとみたやコード全体を要求してきました。今度はこっちがなかなかバグを治せない初心者エンジニアみたいです… かわいい 最後にお礼にコードレビューしてみると…? GPT-4の使用上限にひっかかって、GPT-3.5になりました。。。コンテキストをちゃんと解釈してくれてない回答感ありますよね…KY… ChatGPTと喋った内容 Takaaki # 命令書: あなたはフロントエンドエンジニアです。 以下の制約条件と入力文をもとにゲームのソースコードを出力してください。 # 制約条件: * HTML、CSS、Javascriptのみで動く # 入力文: テトリス # 出力文: ChatGPT 以下は、HTML、CSS、Javascriptを使用してテトリスゲームを実装するための簡単なソースコードです。このコードをhtmlファイルにコピーして実行することができます。 <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>テトリス</title> <style> body { font-family: Arial, sans-serif; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; } canvas { border: 1px solid #000; } </style> </head> <body> <canvas id="game" width="320" height="640"></canvas> <script> const canvas = document.getElementById("game"); const context = canvas.getContext("2d"); const scale = 20; context.scale(scale, scale); const arenaSweep = () => { outer: for (let y = arena.length - 1; y > 0; y--) { for (let x = 0; x < arena[y].length; x++) { if (!arena[y][x]) { continue outer; } } const row = arena.splice(y, 1)[0].fill(0); arena.unshift(row); ++y; } }; const collide = (arena, player) => { const [m, o] = [player.matrix, player.pos]; for (let y = 0; y < m.length; ++y) { for (let x = 0; x < m[y].length; ++x) { if (m[y][x] && (arena[y + o.y] && arena[y + o.y][x + o.x]) !== 0) { return true; } } } return false; }; const createMatrix = (w, h) => { const matrix = []; while (h--) { matrix.push(new Array(w).fill(0)); } return matrix; }; const draw = () => { context.fillStyle = "#000"; context.fillRect(0, 0, canvas.width, canvas.height); drawMatrix(arena, { x: 0, y: 0 }); drawMatrix(player.matrix, player.pos); }; const drawMatrix = (matrix, offset) => { matrix.forEach((row, y) => { row.forEach((value, x) => { if (value) { context.fillStyle = "red"; context.fillRect(x + offset.x, y + offset.y, 1, 1); } }); }); }; const merge = (arena, player) => { player.matrix.forEach((row, y) => { row.forEach((value, x) => { if (value) { arena[y + player.pos.y][x + player.pos.x] = value; } }); }); }; const playerDrop = () => { player.pos.y++; if (collide(arena, player)) { player.pos.y--; merge(arena, player); playerReset(); arenaSweep(); } dropCounter = 0; }; const playerMove = (offset) => { player.pos.x += offset; if (collide( #### Takaaki 続けてください #### ChatGPT arena, player)) { player.pos.x -= offset; } }; const playerReset = () => { const pieces = "TJLOSZI"; player.matrix = createPiece(pieces[(pieces.length * Math.random()) | 0]); player.pos.y = 0; player.pos.x = ((arena[0].length / 2) | 0) - ((player.matrix[0].length / 2) | 0); if (collide(arena, player)) { arena.forEach(row => row.fill(0)); alert("ゲームオーバー"); } }; const playerRotate = (dir) => { const pos = player.pos.x; let offset = 1; rotate(player.matrix, dir); while (collide(arena, player)) { player.pos.x += offset; offset = -(offset + (offset > 0 ? 1 : -1)); if (offset > player.matrix[0].length) { rotate(player.matrix, -dir); player.pos.x = pos; return; } } }; const rotate = (matrix, dir) => { for (let y = 0; y < matrix.length; ++y) { for (let x = 0; x < y; ++x) { [matrix[x][y], matrix[y][x]] = [matrix[y][x], matrix[x][y]]; } } if (dir > 0) { matrix.forEach(row => row.reverse()); } else { matrix.reverse(); } }; const createPiece = (type) => { if (type === "T") { return [ [1, 1, 1], [0, 1, 0], [0, 0, 0] ]; } else if (type === "J") { return [ [0, 1, 0], [0, 1, 0], [1, 1, 0] ]; } else if (type === "L") { return [ [0, 1, 0], [0, 1, 0], [0, 1, 1] ]; } else if (type === "O") { return [ [1, 1], [1, 1] ]; } else if (type === "S") { return [ [0, 1, 1], [1, 1, 0], [0, 0, 0] ]; } else if (type === "Z") { return [ [1, 1, 0], [0, 1, 1], [0, 0, 0] ]; } else if (type === "I") { return [ [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0] ]; } }; let dropCounter = 0; let dropInterval = 1000; let lastTime = 0; const update = (time = 0) => { const deltaTime = time - lastTime; lastTime = time; dropCounter += deltaTime; if (dropCounter > dropInterval) { playerDrop(); } draw(); requestAnimationFrame(update); }; #### Takaaki 続けてください #### ChatGPT const arena = createMatrix(10, 20); const player = { pos: { x: 0, y: 0 }, matrix: null }; document.addEventListener("keydown", event => { if (event.keyCode === 37) { playerMove(-1); } else if (event.keyCode === 39) { playerMove(1); } else if (event.keyCode === 40) { playerDrop(); } else if (event.keyCode === 81) { playerRotate(-1); } else if (event.keyCode === 87 || event.keyCode === 38) { playerRotate(1); } }); playerReset(); update(); </script> </body> </html> このコードは、テトリスゲームの基本的な機能を実装しています。プレイヤーは矢印キーを使ってピースを操作し、Qキーで反時計回りに回転、Wキーまたは上矢印キーで時計回りに回転させることができます。行が埋まると消え、ゲームが続行します。ピースがスタックして画面上部に達すると、ゲームオーバーになります。このコードを自由にカスタマイズして、さらに機能を追加したり、見た目を改善したりすることができます。 ...

April 16, 2023 · 15 min

Makefileで改行文字を扱う

最近、Github CLIの存在を知って使いこなそうと頑張っている。 その中のコマンドの1つとしてPRを作成するコマンド gh pr create がある。 https://cli.github.com/manual/gh_pr_create オプションの1つである --body を使えば、PRのbodyもコマンドラインから渡せてしまう。 gh pr create --web --body " ### What プルリクエストをコマンドラインから作成してみた " ただし、これをMakefileの中でやろうとすると以下のようなエラーになる。 # Makefile create-pr: gh pr create --web --body " ### What プルリクエストをコマンドラインから作成してみた " # execute `make create-pr` gh pr create --web --body " /bin/sh: -c: line 0: unexpected EOF while looking for matching `"' /bin/sh: -c: line 1: syntax error: unexpected end of file make: *** [create-pr] Error 2 Makefileの中では1行1コマンドとして解釈されてしまうため、ダブルクオーテーションの終わりを探してくれない。 ...

August 15, 2022 · 1 min

Vimのヤンクレジスタを使いこなしたい

大学4回生からプログラミングを始めて、Atoms、Sublime Text、VS Code、IntelliJといろんなエディタを触ってきましたが、社会人になってからVimをずっと使い続けています。 最初は慣れないキーストロークでノロノロコーディングするのが苦痛でしたが、今ではVim以外でトラックパッドを触るのがめんどくさいと感じるようになってきました。 といってもまだまだVimを使いこなせておらず、工夫すれば簡単に終わりそうな操作があってもコーディングに集中したく、Vimの使い方を調べることは少ないです。 しかし、よくある操作でいつもうまくできない「単語をコピーして入れ替える」についてやっとちゃんと調べることにしてみました。 参考 この本の抜粋になります。 https://www.amazon.co.jp/dp/4048916599/ よくある間違い キーストロークバッファの内容yiwcollection = getCollection();process(somethingInTheWay, target);jwwcollection = getCollection();process(somethingInTheWay, target);diwcollection = getCollection();process(, target);Pcollection = getCollection();process(somethingInTheWay, target); 初期の頃にやっていたとてもあるあるの行動です。ただ単語を削除してヤンク(コピー)した単語をはりつけたいだけなのですが、単語を削除した際に無名レジスタに削除した単語が格納されてしまうため、そのままPut操作を行うと、削除した単語が貼り付けられてしまいます。 Visual modeを使った回避策 いままでよくやっていたのがこの方法です。 キーストロークバッファの内容yiwcollection = getCollection();process(somethingInTheWay, target);jwwcollection = getCollection();process(somethingInTheWay, target);vecollection = getCollection();process(somethingInTheWay, target);pcollection = getCollection();process(collection, target); こうすると選択対象と削除とヤンクした単語の貼り付けが同時に行われるので、削除した単語がはりつけられることはなくなります。しかし、入れ替えたい対象が2箇所以上あった時に、この操作をした後にはすでに無名レジスタには somethingInTheWay が格納されてしまっています。 ブラックホールレジスタを使った回避策 Vimには "_ というブラックホールレジスタ(消去専用レジスタ)が用意されています。保存したいわけではなくただ削除したのであれば、このレジスタにつっこめばいいわけです。これを使うと、先ほどの問題が解決します。 キーストロークバッファの内容yiwcollection = getCollection();process(somethingInTheWay, target);jwwcollection = getCollection();process(somethingInTheWay, target);"_diwcollection = getCollection();process(, target);Pcollection = getCollection();process(collection, target); ただちょっとめんどくさいですよね? いちいち単語を削除するときはブラックホールレジスタに入れんとあかんから "_ を削除前に指定して…と考えることが多くなります。 ヤンクレジスタを使った回避策 おそらくこれが正解です。 キーストロークバッファの内容yiwcollection = getCollection();process(somethingInTheWay, target);jwwcollection = getCollection();process(somethingInTheWay, target);diwcollection = getCollection();process(, target);“0Pcollection = getCollection();process(collection, target); ...

August 13, 2022 · 1 min

富士山の須走ルートを日帰りで登ってみる

たまにはエンジニアリング全く関係ない記事を書いてみます。 富士山に登るのは初めでではなくて、大学3回生の時に吉田ルートから山小屋を使って山頂まで登ったことがあります。 とまあ台風が直撃して生憎の天気だったので、去年に富士宮ルートから山小屋泊ありでもう一度チャレンジしたのですが、またまた台風がきて…山頂まで登れず8合目から引き返して6合目で宿泊し下山することに… 今年再チャレンジしたかったのですが、なかなか山小屋を取ろうとするとあらかじめ日程を決める必要があり天気にされるのと、社会人になってしまったため1泊2日にすると休養日が取れないのと、相方が山小屋に泊まりなくないという諸々の理由から、日帰りで富士山に登るチャレンジをしました! 準備 7/16~18の3連休に何の予定もないことに気づいて、7/13に思い立って準備を始めました。 まずルートです。吉田ルートと富士宮ルート(山頂まで登れてないですが)の経験があったので、須走ルートにチャレンジすることにしました。 http://fujisan-climb.jp/trails/index.html 次に宿です。開山中は富士山マイカー規制がかかっているので、須走ルートの5合目の登山口に行くには道の駅すばしりから出ているシャトルバスに乗る必要があります。 http://www.pref.shizuoka.jp/kensetsu/ke-210/fujisan/ 日帰りの登山なので朝一番に登りたく、始発の6:00に着きたいです。なので、この場所に近いところに泊まれば睡眠時間が確保できるかなと思い、裾野セントラルホテル寿々木に止まって4:30におきてレンタカーで向かいました。 あとは、登山用具です。現地で借りる手段をさがしたのですが、なかなか朝早くにやっていなかったり返す時間が18:00までとちょっと不安だったりで見つからなかったのですが、登山用品のネット宅配レンタル専門店 神戸アウトドアを使って全て解決しました。 https://www.kobeoutdoor.com/ 3日前だったのに移動日の土曜の朝までに届きましたし、前日にパッキングできますし、返す時もコンビニで汚れたまま返却できてめちゃ快適でした。 いざ登山 いよいよ当日7/17、4:30に起きるのは辛すぎましたがコンビニで食糧も調達して道の駅須走へ。5:45ぐらいについたのですが、シャトルバスに行列ができていて始発に乗れませんでした…10分後ぐらいに臨時の2本目がきて耐えました… 6:30ぐらいに5合目に着いて、30分体を慣らして7:00過ぎに出発。最初若干雨が降っていたんですが、だんだんやみつつレインコート脱ぎつつ進んで行きました。 6合目についたのが9:50です、公式には60分とあったのですがサボりすぎました。。。 http://fujisan-climb.jp/trails/subashiri/course.html あわててガンガン進むことに。7合目には11:00につきました。 このあたりから私が高山病になりはじめ、歩みがとても遅くなり… 本8合目に13:20ごろについて、 14:45になんとか山頂まで辿り着きました! 公式では6時間で登れるとあったのですが、7時間45分かかっています…公式の人の足早すぎです… このチリトマトめちゃおいしかったです。これをやるためにもう一度登ったまであります。 そこから砂走りをひたすらひたすらひたすらひたすら降ること4時間ぐらいですかね…18:45ぐらいに5合目までに辿り着いて最終のシャトルバスに乗ることができました。公式が3時間で下山できると書いていますが、とてもとてもでした。体力というよりいかに無心で足を動かすかという精神力の戦いでした。 まとめ 日帰りで富士山は登れますが、とても過酷です!!!!!!!!!!!!!!!!

August 13, 2022 · 1 min

AWSのアカウントは分けると安心

自分がAWSを触ったのは、大学院時代に友達と簡単なWebサービスをデプロイするときに使ったのが初めてでした。1通り基本的なことを学ぶために、udemyの教材を使って基本的なリソースをマネジメントコンソールから作って削除していました。 そういった個人的な開発をする中ではなかなかAWSアカウントを複数作ることはなく、1つのAWSアカウントの中にサーバーやデータベースを作ることが多いです。 しかし、現職に入社してIDaaS経由でAWSの権限をもらったときに大量のアカウントが表示されていてびっくりしました。今ではとても理に適った管理方法だなと思うので、その感想をつらつら書きます。 参考 AWSのマルチアカウント戦略ってなに?なぜ必要?【社内勉強会スライド】 https://dev.classmethod.jp/articles/why-aws-multi-accounts/ メリット 権限が分離されている安心感がすごい 現職ではサービスの環境をDevelopment、Staging、Productionの3種類にわけていて、アプリケーションをEKSで動かしています。 1つのAWSアカウント内でこれをやろうとすると、環境ごとのVPC、IAM Role、EKSクラスタを作ったりする必要があり、ちゃんと分離できているのかが不安になります。 しかし、環境ごとにAWSアカウントを作成するとこんな感じになります。 お互いが絶対に干渉しないので、内部の設定ミスによる事故を防いだり、外部からの攻撃の影響範囲を制限することにつながります。 工夫が必要な点 初期に必要なAWSリソースをCloudFormationで作成 Terraformを使って各AWSアカウントのリソースを管理したいところですが、初期の状態ではTerraformを実行するためのIAM Roleもないわけです。それをアカウントごとに作成するのは大変なので、CloudFormationを使って最低限必要なリソースを全てのアカウントに対して作成します。 AWS Organizationを使ってAWSアカウントをOrganization Unit単位でグルーピングしておけば、より細かいリソース作成が可能になります。 Transit Gatewayを使ってAWSアカウントをまたがった通信を行う 各サービスにおいてEKSクラスタを共有させたいが、DBやStorageは別アカウントで持たせたいということもあると思います。実現する方法の1つとして、Transit Gatewayを用いる方法が挙げられます。 この記事をとても参考にさせてもらいました🙏 Transit Gatewayを利用してVPC間で通信してみた https://dev.classmethod.jp/articles/transit-gateway-vpc/ まとめ 現職でプロダクトの開発に携わりながら、こういったインフラを扱うSREのタスクもやらせてもらっていて、学んだことを残していこうと思います💪

July 31, 2022 · 1 min

Goのエラーハンドリングが好き

Goとの出会い 自分がGoを触り始めたきっかけは、大学院1回生の時に研究室の先輩と一緒に出たISUCONでした。パフォーマンスの観点でGoがめっちゃいいらしいからGoで出ようってなって、Go Tourなんかで勉強してました。 当時なんでもGithubにpushしたい病だったので、よーわからんリポジトリもありました。 https://github.com/adshidtadka/go_tour エラーハンドリングがめんどくさい そもそもプログラミングをちゃんと始めたのが大学4回生のDonutsでのアルバイトで、経験が浅いなんちゃてプログラマーでした。つまり、エラーハンドリングなんてかったるいと思っているわけです。 そんなマインドでGoのコードを読むと、どんな関数もerrorを返してくることにびっくりします。 こんな感じで何か関数を呼び出すとすかさずerrorが帰ってくるので、いちいちエラーハンドリングを書くのがめんどくさく握りつぶしたいという思いに駆られることが幾度となくありました。 type Result struct{} func doSomething(code string) (*Result, error) { if code == "ok" { return &Result{}, nil } return nil, errors.New("エラーだよ") } func main() { _, err := doSomething("error") if err != nil { // エラーハンドリングをいちいち書かされる } } 他の言語の多くにはtry-catchの仕組みがあるので、こっちのが絶対便利とか思っていました。 type Result = {}; const doSomething = (code: string): Result => { if (code === "ok") { return {}; } throw new Error("エラーだよ"); }; const main = () => { try { const result = doSomething(); } catch (e) { // ここ1箇所でまとめてエラーハンドリングできる } }; やっぱりエラーハンドリングしたい 大学3年、社会人2年の時を経て考え方が変わりました。関数たちに対して思うことはエラーを勝手にthrowせずにちゃんと返して欲しいと思うようになりました。 その理由の一例がこちらです。最近プロダクトを開発する中で、不具合調査に時間がかかった例でもあります。 type Result = {}; const doSomething = (code: string): Result => { if (code === "ok") { return {}; } throw new Error("エラーだよ"); }; const main = () => { try { const result = doSomething(); const result2 = doSomething(); // こいつが呼ばれるかどうかわからない } catch (e) { } }; try句のコードは全て呼ばれるわけではないのです。勝手にジャンプしてcatch句にいく可能性を考えてコーディングする必要があります。try句には長い処理を書かない方が無難でしょう。 ...

July 16, 2022 · 2 min

React Hooksに対するテストを書いていきたい

ご無沙汰しております。会社のプロダクトチームの新しいメンバーの方がGoのLT会に出ておられて、自分もそういった個人での活動をしたくなった次第です。 React Hooksとは 以下の公式ドキュメントが詳しいです。 https://ja.reactjs.org/docs/hooks-intro.html 前職ではAngularで開発を行なっていたのですが、コンポーネントを定義するためにクラスを定義していて、意図しないタイミングでインスタンス変数が書き換わっているみたいなことがザラにありました。 Hookがない時代のReactも触ったことがあったのですが、同じようにクラスを定義してごにょごにょしなければいけないイメージがあって、現職でReactを触り始めるまではAngularもReactもさして変わらんでしょ、と思っていました。 結論、ReactのHookによりReactがとても気に入りました。関数でコンポーネントを定義できるので理解しやすく挙動も予想しやすいですし、カスタムHookを定義することでコンポーネントのロジックの部分だけを簡単に再利用することができます。 なぜHookに対してテストを書くの? Hookはコンポーネントのロジックを司る部分であるため、テストが書きやすく実行も早いからです。 Hookだけでなく、コンポーネントに対してももちろんテストを書くことができます。以下のレシピ集においても、DOMどんな要素が描画されているのかをテストする方法が示されています。 https://ja.reactjs.org/docs/testing-recipes.html しかし、DOMに対するテストは書きにくいです。評価する部分を書く際にcontainer.querySelector("strong").textContent みたいな感じで要素にアクセスする必要があるのですが、DOM構造を知っていないと書けません。要素があるかないかではなくDOM構造をテストしたいのであれば、テストを書くのではなくStorybookなんかを使って見た目を確認する方が本質的です。 また、DOMに対するテストは実行に時間がかかります。DOMの描画自体に時間がかかるというのもありますし、依存しているコンポーネントもビルドしなければならないという原因もあります。 前職ではDOMに対するテストがビルド時間短縮のボトルネックになっていて、JasmineからJestに移行することでいくらか速くならないかみたいなことを試行錯誤していました。 そこで、Hookに対してテストを書くわけです。HookにはDOM構造の概念がなく、stateに対して評価が書けます。DOMを描画する処理もなく、他のHookに依存しているみたいなことも少ないです。 どうやって書くの? 以下のドキュメントにある書き方を拝借させていただきます。 https://react-hooks-testing-library.com/usage/basic-hooks こんな感じのカスタムHookがあれば、 import { useState, useCallback } from 'react' export default function useCounter(initialValue = 0) { const [count, setCount] = useState(initialValue) const increment = useCallback(() => setCount((x) => x + 1), []) return { count, increment } } こんな感じでテストがかけます。 import { renderHook, act } from '@testing-library/react-hooks' import useCounter from './useCounter' test('should increment counter from custom initial value', () => { const { result } = renderHook(() => useCounter(9000)) act(() => { result.current.increment() }) expect(result.current.count).toBe(9001) }) よくないですか?? 評価対象がHookの返り値としてreturnされるので、result.current.count みたいにさくっとアクセスできちゃいます。Hook内で作ったCallbackを呼び出したい時も、結局Hookの返り値としてreturnされるので、result.current.increment() みたいにさくっと呼び出せちゃいます。 ...

July 9, 2022 · 2 min