• 車種別
  • パーツ
  • 整備手帳
  • ブログ
  • みんカラ+

ヒデノリのブログ一覧

2025年09月16日 イイね!

アルテシマが激成長してきました。

アルテシマが激成長してきました。お部屋にグリーンを取り入れたいなら、アルテシマはいかがでしょうか。正式には「フィカス・アルテシマ」といい、ゴムの木の仲間で、その育てやすさから初心者にも大人気です。

最大の特徴は、ライムグリーンの斑入りが美しいつややかな葉。お部屋に置くだけでパッと明るい雰囲気を演出してくれます。また、「永遠の幸福」という花言葉を持つことから、新築祝いや結婚祝いなど、お祝いのギフトとしても喜ばれています。

育てる上でのポイントは、日光を好むので明るい場所に置くことと、水やりの頻度を季節によって変えることです。春から秋は土が乾いたらたっぷりと、冬は乾燥気味に管理しましょう。

もし、葉が落ちてきたら、それは環境の変化や水の与えすぎ・不足のサインかもしれません。アルテシマの小さな変化に気づいて、素敵なグリーンライフを楽しんでみませんか?
------------------------------------------------

タイトル画像では縮小されてしまいましたので、
Googleフォトの新しいアカウントから画像を貼り付けました。
フィカス・アルテシマですが、
斑入りと言われる白い部分が多い個体を買ってきたものの、
室内の明るいところで育てていたものの
斑といわれる白い部分が少なくなってまいりました。

これは日光が足らないのか?
しかし、オリーブは別として一般的な観葉植物は直射日光はNGでは?
と思っていたのですが、
今年の夏前にベランダにオーニングをしたのに合わせて
室内の観葉植物全てをベランダに出しました。

特に、日光の当たる量が少ないと思われているフィカス・アルテシマは
ベランダの西側手すりに置いておきました。

すると・・・
見事な斑入りに復活!

この斑の入り方はすごくないですか?

アルテシマはかなり強い光が必要なのですかね?
---------------------------------------------
ゴムの木には他に仲間がおりまして
フィカス・ウンベラータ
というのがおります。


こちらは斑が入ることなく、斑も単色なのですが、
なにがすごいってアルテシマと比べてあかから様に生地がすごい(・・;)

こんなに大きくなるん?(・・;)

今年の夏は暑かったのですが
我が家の植物にとっては快適だったようで、
数ヶ月でものすごく成長してくれました。

その部はちょくちょく小出しにしていきたいと思いますm(_ _)m
Posted at 2025/09/16 23:49:03 | コメント(1) | トラックバック(0) | 日記
2025年09月15日 イイね!

政府備蓄米も行き渡ってきたのかな?

政府備蓄米も行き渡ってきたのかな?近所のダイレックスに寄ったらたまたま政府備蓄米が大量に置いてありました。

我が家のお米が少なくなっていたので、
ビールを買うついで買いしたのですが、
たまたまだったようですね^^;
Posted at 2025/09/15 20:33:32 | コメント(0) | トラックバック(0) | 日記
2025年09月14日 イイね!

語弊ある言い方かもしれませんがエンジニアに失敗は無い

語弊ある言い方かもしれませんがエンジニアに失敗は無いちょっと前にブログを投稿しましたが、
新プロジェクトXのH3ロケット打ち上げを見返して見て思いが高ぶってしまい連続投稿失礼しますm(_ _)m

語弊ある言い方かもしれませんがエンジニアという職業は割り切れてしまえば、
結果を見ると私からすると一番楽な職業なのかもしれません。
ただし、その途中では最も過酷な職業に思います。

我々は日本人で失敗を恐れることに対して、
何故そうなったのかは興味を持って調べていないのでわかりませんが、
何故か失敗することがネガティブな評価を自信からも周りからも行われるということを
日本人は何よりも恐れているように思います。
確かに、共通テスト(私が受けた当時はセンター試験)というマークシートを元に、
例えば東大では足切りと言われるセンター試験の結果を持って
2次試験を受ける資格が与えられないという状況がありました。

私の部下も失敗を恐れるような働き方を思っているようですが、
私の伝え方が足らないのをとても部下に対して申し訳なく思います。

エンジニアという立場の方にはプロジェクトを成功する事が望まれています。
ですが、今までの実績のあるやり方がわかっている作業であれば
そもそもプロジェクトが組まれないと思っています。

プロジェクトが組まれるというのは、
今まででは駄目とトップが思ってブレークスルーを求めるために組まれるものだと思っています。

つまり、エンジニアには会社(プロジェクト)がどうしようもない状況に陥って
それをなんとかしたいと思ってすがってきたものだと思っています。

これまでの実績が通用しない状況で、
新しいことを実現してくれるであろう期待値からエンジニアが呼ばれるのだと思います。

ここまでが導入です。
--------------------------------------------
プロジェクトに組み入れられたエンジニアはどうするのか?
今までの実績を調べるのは当然のこと、
今まで無かった技術を開発することを求められるわけです。

今まで無かった技術を開発するということなので、
前例のない事を実現することが求められるわけです。

無いものを作れ!

令和の今どきであればふさわしくない言葉かもしれませんが、
どうしようも無くなってエンジニアに求める能力というのはそういうものです。
--------------------------------------------
それに対して、いゃ俺に言っても・・・
前例のないことに対して何を求めているん?
とお思いの方が大多数だと思います。

私も50歳手前まで、ごく最近(数年前まで)そう思っていました。

ですが、大きなプロジェクトをいくつか任されて、
ある日突然振り返ったときに思い立ちました。
--------------------------------------------
そういう大きなプロジェクトって興味を持つことが重要なのでは?

プロジェクトを任されたときに最初に思うことは、
自分の手に余るか余らないか?
ということだと思います。

自分の手に余ることであれば今までの経験で出来ることですし、
自分の手に余らないことであれば・・・
言い方を変えると今の自分にできないことを求められるチャレンジングな目標ということになると思います。
--------------------------------------------
とある、ネットワークエンジニアリングの教科書で以下の様に表現されていました。
エンジニアとして一番成長していると実感できるのは顧客先で四苦八苦してるときだと・・・

つまり、顧客先で膨大な失敗を繰り返しながら
成功に導こうと延々と繰り返している時がエンジニアとして成長できる機会であると言っていました。
--------------------------------------------
また、バックプロパゲーション(誤差逆伝播法)とは、
ニューラルネットワークの学習において、ネットワークの出力と正解データとの差(誤差)を、出力層から入力層に向かって逆方向に伝播させ、各層の重みとバイアスを調整することで、ネットワークの性能を向上させるアルゴリズムです。
この手法は、ディープラーニングの基盤技術として広く普及しています。
--------------------------------------------
つまり、失敗経験を上手くいく方法を教えることなくスパルタ的に教えているわけです。

AIと人間の脳に本質的な違いは無いということから、
学習の仕方に最短距離というのはなく、
結局のところバックプロパゲーション(誤差逆伝播法)を行うしか無いというわけです。
--------------------------------------------
後半をご覧になっていくと失敗は行っはいけないものなのか?
失敗することもあるのでは?
という事を思われるかもしれません。

私は自分でエンジニアとして過ごしてきて、
認知できる大きなプロジェクトとしては
受注システム(Order Manegement System=OMS)の導入です。

OMSの導入は会社としては相当大きなプロジェクトだったのですが、
最初は担当者で合ったものから最終的に責任者にまで上り詰めました。

OMS導入と言っても我が社には知見がない状態での導入になりますので、
試行錯誤を繰り返すことになります。
しかも先方に導入担当というのがいない状況です。

ならば、自分たちでどうにかするしか無いという状況になります。

プロジェクトを日々進める上で沢山アイデアが出てきます。
仕事中に集中しているので、
休日にそのアイデアが出てくることも止めることが出来ませんが、
日本の世の中では1日8時間、1週で40時間以上働くことは法律で認められていなので自重していましたが、
興味を持ったことに対してその欲求が湧き上がってくるのは止めようがありません。

なので、ふとした時にアイデアが出てくるのを無理やり押さえつけるという日々を過ごしていました。

アイデアは興味を持って取り組むことで無限に湧き上がってくるのですが、
それを見つめ直したときに有用なアイデアと言うのは
100件中1~2件あれば良い方
という状況でした。
ですが、初めてのことを行うのでそれに対して悲観するものではなく、
新しいプロジェクトを行うにはそういうものだと何となく理解していました。
--------------------------------------------
思いついたアイデアの1~2%しか採用されないの?
とお思いの方もいらっしゃるかもしれませんが、
逆に言うと98~99%は失敗してもその失敗が会社に認識されないということになります。

アイデアの全てをプロジェクトに報告することは無いと思いまして、
業務時間中にそのアイデアを自身で可能な範囲で検証るというのを繰り返していくと思います。

という事は、エンジニアが行う成果に対して、
失敗は99~90%近くが失敗していたとしても認識されないということになりますし、
その失敗経験はそのエンジニアにとって貴重な資産になるというわけです。
--------------------------------------------
私の持論ですが、
----------------------------------------
あらゆる興味に対して勉強する姿勢で失敗は決して無い。
失敗はやり遂げられなかったという事実によって発生する。
----------------------------------------
間違いを恐れない。
諦めたことこそが失敗であり、
やり遂げたことこそが人生の成功体験である。
----------------------------------------
というのがあります。

何度か登場しているのでご存じの方もいらっしゃると思います。

新しいことを行うことに対してエンジニアは人間なので
必ず失敗します。
ですが、その失敗を糧に前に進むことが出来ます。
その失敗を繰り返しながら前に進んで成功まで導いた結果は、
そのエンジニアはプロジェクトを成功させたという評価になります。

このことから
----------------------------------------
あらゆる興味に対して勉強する姿勢で失敗は決して無い。
失敗はやり遂げられなかったという事実によって発生する。
----------------------------------------
というのが言えるかと思います。

興味を持ってやりたいことに対して、
業務時間外にそれを知りたい欲求を抑えることは出来ませんし、
失敗を糧に進むのを日常にすることで、
成功まで導いたという事実に対して
プロジェクトはそのエンジニアは完遂させたと評価します。

全く新しいことをすることに対して、
いわゆる教科書の内容が通じない状況でも、
新しいことを生み出すことを求められる状況に対して、
すでに述べましたが
興味を持つ
というのが一番大切だと思います。

ごく最近、意識的に行っている開発手法なのですが、
新しい開発を行う際にまず興味を持つことからはじめまして、
業務時間にそのことに対して興味を持ってやり遂げたいという気持ちを持って一生懸命考える。

業務時間中に解決できる問題ならば簡単に出来る問題だったと認識し、
業務時間で解決できない問題はチャレンジングな目標と認知する。

チャレンジングな目標は引き続き、
業務時間内で繰り返し一生懸命考える。

それでも解決できない問題はいったん据え置く。

え?時間をかけて業務時間外でも考えるんじゃないの?
とお思いの方もいらっしゃると思いますが、
考えているときの神経回路の電気の流れ方は、
行わないといけない回路周辺しか流れません。
----------------------------------------
一方、脳にはデフォルト・モード・ネットワークという状況が存在します。

何かに対して一生懸命考えている時は、
それを解決するためにそのためだけの周辺の回路が活性化している状況です。

ですが、脳の回路と言うのは想像を絶する神経回路が存在しているので、
なにかに集中している状態と言うのは回路の一部しか働いていない状況となります。

話がそれますが、
いわゆる精神疾患でうつ病と言われる方々の気持ちが落ち込む状況は、
症状を発生していないどなたにも発生する危険性をはらんでいますが、
それに対して改善する方法はマインドフルネスという方法があります。
これは、自身の息を何秒間吸って何秒間吐くというのを繰り返すというのも一つの方法とされています。
また、前に向かって進むウォーキングもいい方法とされています。
さらに、ハイキングも眼の前の坂を登ることに集中するのでいい方法とされています。

うつ病などの気分が落ち込む状態と言うのは、
なにかに集中できない状態で脳が暴走していることから発生していることが言われてます。

そのために、呼吸やウォーキング、ハイキングを日常的に行うことで脳の暴走を抑えることで脳を休めるということが言われています。

この事は、脳科学者の茂木健一郎さんが
脳を休める方法はそれまでとは全く別のことに集中する
と言っていることから伺えます。
----------------------------------------
一生懸命考えていることで、
脳の神経回路の動作する場所を意識的に狭めているのであれば、
うつ病などの神経疾患を患っている方が多く落ちっている状況のデフォルト・モード・ネットワークに意識的に投入させることで、
新しいアイデアが出てくるのではないか?
と思った次第です。

これが、私の提唱する
今の自分に解決できない問題を解決する最短方法
と思っています。

問題に対して一生懸命考える。
それで解決できる問題であれば良し。

そうでない問題であれば更に業務時間中に考える。

そうすると、業務時間外にそのもんだいについて頭に浮かぶ時が来ます。
それは知りたい欲求なので考えたくなりますが、
その欲求を意識的に抑えることをします。

時間外は趣味に使える時間だから業務の問題を知りたい欲求をあえて考えないようにします。

ですが、その欲求を抑えることは出来ず、
抑えても一定時間後に出てくるのですがそれでも抑えることをします。

これを繰り返すことで、
無意識下で問題解決を行うための回路が出来ていくのではないかと思っています。

そうする中で、業務時間中にふと時間が空いたときであったり
ハイキングを行っている中で坂の傾斜が穏やかになったときであったり、
お風呂を洗っている中で泡をシャワーで流そうとした瞬間であったり
何も考えない時間というのが日常生活で存在する中で、
脳はデフォルト・モード・ネットワークに一瞬で突入すると思っています。

デフォルト・モード・ネットワークと言うのは
脳の神経回路の暴走状態でうつ病などの神経疾患をお持ちの方にはデメリットでしか無いのですが、
今までの経験では実現不可能な目標を解決するにはデフォルト・モード・ネットワークに投入させることを何度も繰り返すことでしか出来ないのではないかともいます。

確かに、脳科学者の茂木健一郎さんを始めとした様々な功績を残した方の言葉を振り返ると、
ふとした瞬間にひらめいた
というのがあります。

という事は、一生懸命に問題解決する時間を繰り返しながら
デフォルト・モード・ネットワークに意識的に残す時間を作ることから、
今まで出来なかった問題を解決することを高速で行うのではなかろうかと思っています。
----------------------------------------
エンジニアという人種は日常のあらゆることに対して興味をいただきます。
それに対して知りたいという欲求が高まってきます。

それに対して突き詰めるのは研究者であって、
エンジニアはその道具を使って他のものと接続する方法を探すというのを
行っているのだと思います。

突き詰めるのではなく、
それに対して興味を持って真理や設計思想を知りたいと思って
それが他のものと繋がる方法を無意識下で探して、
設計者が当時では意図しない
設計を超えた方法で他のものと接続する方法を探す事を
史上の喜びのように思っています。
----------------------------------------
エンジニアに対して求められる能力・・・
今まで無かったものを開発す能力・・・

バックプロパゲーション(誤差逆伝播法)・・・

あらゆることに対して興味を持つ姿勢・・・

その興味に対して業務時間中に真剣に考える姿勢・・・

その興味に対して休日に湧き上がる興味とそれをあえて押さえつける姿勢・・・

うつ病などの神経疾患でとても悩んでいる
デフォルト・モード・ネットワークを意識的に作ることでの問題解決・・・
----------------------------------------
100個のアイデアが出る中で1~2個のアイデアが採用されるというのを日頃体感していたら、
失敗は日常というのが嫌でもわかってくると思います。

という事は、諦めずに失敗し続けるという姿勢を貫く限り
エンジニアに対して失敗は無いのだなと思いました・・・
----------------------------------------
タイトルに戻りますが、
エンジニアに失敗は無い
というのは、
エンジニアの失敗は日常であって、
その日常に対して評価できるのは本人以外にはおらず、
失敗を繰り返してその人の糧を得ることを繰り返すことで
成功まで導いたという事実だけでプロジェクトはそのエンジニアを評価するのだと思います。
----------------------------------------
エンジニアというのはエンジニア語を発するので、
一般の方にとってはエンジニア語での失敗例を理解できません。

そもそもエンジニアの失敗を失敗として認識できません。

それにあぐらを書いているエンジニアは取り残されるので置いといて、
前に進もうとしているエンジニアの方々は、
前例の無いことを行っているのだから
正解までの道しるべを示していない会社のほうが悪いと割り切って
前例のないことに対して興味を持って日常業務をこなして貰えればと思います。
----------------------------------------
エンジニアになるのは簡単です。
日常目にするものに対して興味を持つことから始めます。

それに対して他と繋がる方法を探します。

繋げようとして失敗は有ると思います。
ですが、その失敗はその貴方しか認識できないことです

貴方は貴方の興味を持って前に進むことを行うだけで、
全ての失敗は貴方が前に進む糧として蓄積されていくのです。
----------------------------------------
日常業務に対して興味を持つだけで・・・

失敗を恐れず前に進み続けるだけで・・・

いつでも貴方はエンジニアに成ることが出来ます。
----------------------------------------
年齢など関係ありません。

令和の今どきであれば貴方に合うAIに出会うことで
50歳でも60歳でもエンジニアに成ることは出来ます。
Posted at 2025/09/15 00:16:31 | コメント(0) | トラックバック(0) | 日記
2025年09月14日 イイね!

デジタル一眼レフカメラの保存場所

デジタル一眼レフカメラの保存場所しょっちゅう持ち出していたら、
しょっちゅうズームを使っていたら、
カメラ内外の空気が動くのでカビが生えにくいそうです。

勿体がらずに、しょっちゅう使えってことですよね^^;

と言うものの、
梅雨の時期など雨が降っていて湿度が高い状態はカビが生えやすいという事で、
保管場所を整えることにしました。

予算は可能な限り安く^^;

なにせ、
ボディ:Canon EOS 7D
レンズ:Canon EF-S 18-55mm F3.5-5.6 IS STM
の組み合わせで2.5万円(税込み・送料込み)という状態ですので、
(ネックストラップとCFカードアダプターとSDカードで3,608円)
という低予算で揃えましたので、
ドライボックスに予算を避けることも出来ずに低予算で探さざるを得なくなりました。

良さそうの無いかな~と思って、
ニトリなら有るかな?と思っていって店内をウロウロしていたら・・・

5kgの米びつは?
持っていって車内に置いといたEOS 7Dとサイズを比較すると・・・
シンデレラフィットか!?

米びつは害虫や品質の劣化を防ぐために密封されているようです。

その足でホームセンターに行って
除湿剤にしようか?水とりぞうさんにしようか?
と悩んでいたので
Geminiに水とりぞうさんの除湿能力を聞いたところ・・・
--------------------------------
水取りぞうさんを密封容器で使用する場合、湿度は約40%まで下げられます。

仕組み
「水取りぞうさん」などの除湿剤は、主成分である塩化カルシウム(CaCl
2

)が空気中の水分を吸収することで除湿を行います。塩化カルシウムは潮解性(空気中の水分を吸収して液体になる性質)を持つため、密封された空間の水分を効率よく吸着します。

除湿の限界
理論上、塩化カルシウムは湿度が約35%になるまで水分を吸収し続けることができます。しかし、製品の使用環境や容器の気密性、空気の流れなどの要因により、実際の除湿能力はやや低下します。そのため、一般的に除湿剤が下げられる湿度の目安は40%程度とされています。

この湿度は、日本の高温多湿な気候で、カビやダニの繁殖を防ぐのに有効なレベルです。
--------------------------------
カメラやレンズの保管に最適な湿度は40%~50%前後ということですので、
密封容器ならば水とりぞうさんを組み合わせることで十分ですね。

という事で、令和の今どきで言い方に配慮した表現にすると
コスパに優れる一眼レフカメラのドライボックスは米びつ&水とりぞうさん
ということになりました^^;

令和の今どきであれば決して◯ンボーとか言ってはいけません^^;
差◯だとかいう人が何処から出てくるかわかりませんからね(-_-;)
まぁ、製造から25年も経過した車を持っていたら、
いきなり修理する場所が出てくるので◯ンボーですけどね^^;
良いんです。
チェイサーが良いんです。
ARC presents 西日本スポーツカーフェス2025で、
帰ろうとして車道に向かってゆっくりと動いていたら、
左前の方を車道に向かって走っていく若者二人がいて、
なんで走ってるん?と思ったらどうやら私のチェイサーが出庫するシーンを撮りたかったようで・・・
お前たち、そんなにチェイサーのことをかっこいいと思ってくれるんか!?
という事で、手を降ったりしてちょっとサービスしてしまいました^^;

閑話休題
--------------------------------
ついでに買ったDAISOの温湿度計では30%に張り付いていますが、
この湿度では10%程低く出るようで、
40%という湿度の下限まで下がってくれています。

これならばカビの心配なく保存してくれそうですね。

ただし、湿度の推移をちょくちょく見る必要はあります^^;
Posted at 2025/09/14 21:09:04 | コメント(0) | トラックバック(0) | 日記
2025年09月12日 イイね!

ネクストエンジンとGoogleスプレッドシートをAPI接続できるGASの開発:在庫情報取得_一括処理版編

ネクストエンジンとGoogleスプレッドシートをAPI接続できるGASの開発:在庫情報取得_一括処理版編今日はGPTとコーディングをしていました。
というブログを書いたのが2025年8月17日でしたので、
Google Apps Script(=GAS)の殆ど初心者の私が3週間ほどでここまで来たとは・・・
我ながら感慨深く思います・・・

コーディングが出来る生成AIをどうやって使ってきたのか?
コーディングを行いだしてから2週間の記憶はあやふやですが・・・
・Gemini 2.5 Pro
・GPT-5
を使っていたように思います。

ですが、無料枠では
・Gemini 2.5 Pro
の上限が早々に来てしまったために、そのコードを持って
・GPT-5
にコーディングを依頼するというのを行っていたように思います。

途中でうまく行ったように思いますが、
バージョン管理を行っていなかったために
どうにもならなくなった記憶があります。

コーディングを始めてから2週間が経過した頃に学習したGitHubのブランチと言う知識もありませんでした。

その後、
・GitHub Copilot
を使うためにVisual Studio Code(VS Code)を使いだしました。
タイトルに書かれているのが、
The open source AI code editor(オープンソースのAIと友にコード作成)
ソースは資産という考え方もありますが、
オープンソース化することで開発の速度とコストが向上するというのが有るのでしょうね。
パブリックかプライベートかとう大きな違いはありますが、
かなり有名な会社がGitHubを使用しています。
GitHubとGitHub Copilotは異なるのですが気になったらお気に入りのAIに聞いてみてください。

結構良かったです。
コードの右側にチャットを表示させて、
指示に従ってコードの書き換えを行ってくれました。

ですが、うまく実行するまでに至らず・・・
制限に接触してしまってからAIチャットが使えない・・・(-_-;)

という事で、GeminiだったかGPTだったかは覚えていませんが、
Claude
をオススメされて使いだしたら開発が一気に進みました。

これが、コーディングを始めてから2週間後の出来事です。

2025年9月1日の午前中までVS Code&GitHub Copilotでのコーディングを行っていたものの、
動作するに至らない中で、
無料制限枠に接触してコーディングができなくなったので、
午後からClaudeを使い始めると、
2週間経っても中々進まなかったコーディングが、
わずか半日で認証を終えるところまで進んだのを覚えています。
その間、私のプロンプトエンジニアリング能力も向上したのではないかと思います。
49歳の私が・・・(・・;)

それを検証を終えた状態で公開したブログが
Claudeでのコーディング:ネクストエンジンAPI認証編
となります。

ですが、Claudeも無料枠で使用していたので度々上限に接触してきました。
これが有料枠を契約する理由か(-_-;)

ウチの会社は金が無いから有料枠の契約は出来ないんだろうな^^;

制限にかかりながら進めていって在庫情報の取得が出来るようになったのが、
ネクストエンジンとGoogleスプレッドシートをAPI接続できるGASの開発:在庫情報取得編
です。

ようやく・・・
ようやくここまで来たか・・・(-_-;)

ネクストエンジンとGoogleスプレッドシートを接続したいと思い、
Tepsというアプリを使ってみたり、
SFTPサーバーを立ち上げてCSV連携を自動で行ってみたり、
Yoomというアプリを軽く使ってみたりしましたが、
私の求めるコストと動作をしてくれなくて、
ネクストエンジンとGoogleスプレッドシートをAPI接続するために、
一からGoogle Apps Script(GAS)を生成AIと開発を行ってきて、
GASのプロジェクト内に作成した認証が出来た、
その次にプロジェクト内に新しく作成したスクリプトで200行の在庫情報の取得が出来た!

2週間半でここまで来たか・・・
とても感慨深いです。

ここで、この2週間の間で失敗した経験を元に、
バージョン管理の重要性に気がついて振り返ってみたのが
Visual Studio Code(VS Code)とGitHubの組み合わせです。
-------------------------------------------
Gitは、プログラムのソースコードなどの変更履歴を記録・管理するツールです。たとえるなら、ファイルの「タイムマシン」のようなもので、いつでも過去の状態に戻ったり、誰がいつどこを変更したかを確認したりできます。
-------------------------------------------
GitHubは、Gitの機能を使って世界中の開発者と共同作業を行うためのウェブサービスです。Gitで管理しているプロジェクトをインターネット上で公開・共有したり、他の人と一緒に開発を進めたりする「プロジェクト共有サイト」のような役割を果たします。
-------------------------------------------
Gitは個人のパソコンで動くツール、GitHubはインターネット上のサービスと覚えておくと良いでしょう。
-------------------------------------------
そのGitHubをさらにGUIで使いやすくしたのがVisual Studio Code(VS Code)というわけです。

Claudeで修正したコード全文をVisual Studio Code(VS Code)内で全て貼り付けて保存する(それに加えてコミットとプッシュ?)だけで、
その差分を表示させることも出来ます。

という事で、開発を中断してVisual Studio Code(VS Code)&GitHubの使い方を学ぶことにしました。
開発を進めたほうが前に進むかもしれませんが、
バージョン管理を行わないともとに戻ることが出来ず、
コーディングを始めてから2週間の前に進まない悪夢を再び味わうことになりますので、
開発を中断してでもバージョン管理を行おうとした次第です。
-------------------------------------------
うまく説明できるほどVisual Studio Code(VS Code)を使いこなしていないのですが、
それでもClaudeとコーディングを行っていって、
修正されたコード全文をVisual Studio Code(VS Code)に貼り付けて、
保存・コミット・プッシュすることで、
バージョン管理を行うことが出来るようになりました。

認証が出来た、
200行の在庫情報の取得ができた、
バージョン管理が行うように出来た。

プロの方からすると素人が!と思われるかもしれませんが、
一歩前に進めた瞬間のエンドルフィンが出るのを反芻するために
このコーディングをやっているのだと思います。
-------------------------------------------
認証まで出来て、テストの在庫情報取得まで出来れば、
APIのエンドポイントさえ知っていれば
APIを使って出来る範囲内でどんな情報でも行き来させることが出来るようになると思います。
-------------------------------------------
次に行ったのが1回で取得できる在庫情報の増加なのですが、
そのステップはQiitaでの公開を行うために、
端折って説明すると、
1回で200行の取得(言い換えれば200行までしか取得できない)
だったのを高速化することで1回で300行超の在庫情報が取得できて、
しかも1回の取得可能範囲を超えた在庫情報を取得したい場合、
次に取得する在庫行情報をスクリプトプロパティに残すことで、
1回目の続きから在庫情報を取得できるようになりました。
これで、1000行ほどの在庫情報であれば
1日何回か更新することが出来るようになりました。
これがClaudeで引き続き開発を行うことでわずか4時間(実働時間はもっと短い)
で実装できたことになります。
-------------------------------------------
ん~
なんかモヤモヤ・・
モヤモヤ・・・

とりあえずお昼になったからうどん食べてこよ(笑)

昼から帰ってきて運送会社からアポが合ったので対応して、
コーディングやろうかな~
-------------------------------------------
モヤモヤしてから2時間の間でぼ~っとする時間も合ったことから
脳がデフォルト・モード・ネットワークに入ったことから・・・

ネクストエンジンに対して配列のような形で情報を渡してもらうことで
数十行の在庫情報取得が
APIの1コールで出来るのでは?

と思ってClaudeに
-------------------------------------------
ネクストエンジンとGoogleスプレッドシートを接続して在庫情報を取得するGASの開発を行っていますが、取得する商品コードの数が数千件ある状態です。
今作成しているスクリプトでは1行1行取得していてGASの実行可能時間の上限にどうしても接触している状態です。
これを・・・例えば、数十の商品コードをネクストエンジンに渡して、一気に在庫情報を取得するというようなスクリプトを書くことは可能ですか?
-------------------------------------------
とプロンプトエンジニアリングを行うと
-------------------------------------------
Google Apps Scriptでバッチ処理による効率化は十分可能です。
ネクストエンジンのAPIは複数商品コードを一度に処理する機能を提供していますので、それを活用することで大幅な実行時間短縮が期待できます。
ネクストエンジンAPIには以下のような方法でバッチ処理が可能です:
商品マスタAPI(/api_v1_master_goods/search)を使った方法:
商品コードを配列で渡すことで、複数商品の情報を一度に取得できます。一回のAPIコールで最大100件程度まで処理可能です。
-------------------------------------------
出来るんか~い!
確かに、今までのプロンプトエンジニアリングでは数千行の在庫情報を取得したいとClaudeに伝えたことがないかもしれません(-_-;)

その後、制限にかかりながら出来たコードを公開します。
ハードコーディングしていますが、
テストスプレッドシートですので大丈夫です。

在庫情報取得_一括処理版.gs
-------------------------------------------
/**
* ネクストエンジン在庫情報取得スクリプト(一括処理版)修正版
*
* 【修正内容】
* - async/await構文をGoogle Apps Script対応の同期処理に変更
* - エラーハンドリングを改善
* - デバッグ出力を追加
*/

/**
* スクリプトプロパティの初期設定
* 初回実行時に使用してください
*/
function setupBatchProperties() {
const properties = PropertiesService.getScriptProperties();

// 既存の認証情報は保持して、新しい設定のみ追加
const newProperties = {
'SPREADSHEET_ID': '1noQTPM0EMlyBNDdX4JDPZcBvh-3RT1VtWzNDA85SIkM',
'SHEET_NAME': 'GAS',
'BATCH_SIZE': '100',
'API_WAIT_TIME': '500'
};

console.log('=== スクリプトプロパティ設定 ===');

for (const [key, value] of Object.entries(newProperties)) {
const currentValue = properties.getProperty(key);
if (currentValue) {
console.log(`${key}: ${currentValue} (既存値を保持)`);
} else {
properties.setProperty(key, value);
console.log(`${key}: ${value} (新規設定)`);
}
}

console.log('');
console.log('設定完了!以下の関数でテストを開始できます:');
console.log('- testBatchProcessing(10)');
console.log('- comparePerformance(20)');
console.log('- updateInventoryDataBatch()');
}

/**
* 現在のスクリプトプロパティ設定を表示
*/
function showCurrentProperties() {
const properties = PropertiesService.getScriptProperties();

console.log('=== 現在のスクリプトプロパティ設定 ===');
console.log(`SPREADSHEET_ID: ${properties.getProperty('SPREADSHEET_ID') || '未設定'}`);
console.log(`SHEET_NAME: ${properties.getProperty('SHEET_NAME') || '未設定'}`);
console.log(`BATCH_SIZE: ${properties.getProperty('BATCH_SIZE') || '未設定'}`);
console.log(`API_WAIT_TIME: ${properties.getProperty('API_WAIT_TIME') || '未設定'}`);
console.log('');
console.log('認証情報:');
console.log(`ACCESS_TOKEN: ${properties.getProperty('ACCESS_TOKEN') ? '設定済み' : '未設定'}`);
console.log(`REFRESH_TOKEN: ${properties.getProperty('REFRESH_TOKEN') ? '設定済み' : '未設定'}`);
}

/**
* メイン関数:一括処理による在庫情報更新
*/
function updateInventoryDataBatch() {
try {
console.log('=== 在庫情報一括更新開始 ===');
const startTime = new Date();

// スクリプトプロパティから設定値を取得
const properties = PropertiesService.getScriptProperties();
const spreadsheetId = properties.getProperty('SPREADSHEET_ID');
const sheetName = properties.getProperty('SHEET_NAME');
const batchSize = parseInt(properties.getProperty('BATCH_SIZE')) || 100;
const apiWaitTime = parseInt(properties.getProperty('API_WAIT_TIME')) || 500;

if (!spreadsheetId) {
throw new Error('SPREADSHEET_IDがスクリプトプロパティに設定されていません。');
}

if (!sheetName) {
throw new Error('SHEET_NAMEがスクリプトプロパティに設定されていません。');
}

// スプレッドシートを取得
const spreadsheet = SpreadsheetApp.openById(spreadsheetId);
const sheet = spreadsheet.getSheetByName(sheetName);

if (!sheet) {
throw new Error(`シート "${sheetName}" が見つかりません`);
}

// データ範囲を取得
const lastRow = sheet.getLastRow();
if (lastRow <= 1) {
console.log('データが存在しません');
return;
}

const dataRange = sheet.getRange(2, 1, lastRow - 1, 12);
const values = dataRange.getValues();
console.log(`処理対象: ${values.length}行`);

// トークンを取得
const tokens = getStoredTokens();

// 商品コードのリストを作成(空でないもののみ)
const goodsCodeList = [];
const rowIndexMap = new Map(); // 商品コード → 行インデックスのマッピング

for (let i = 0; i < values.length; i++) {
const goodsCode = values[i][COLUMNS.GOODS_CODE];
if (goodsCode && goodsCode.toString().trim()) {
goodsCodeList.push(goodsCode.toString().trim());
rowIndexMap.set(goodsCode.toString().trim(), i + 2); // 実際の行番号(1ベース)
}
}

console.log(`有効な商品コード: ${goodsCodeList.length}件`);

if (goodsCodeList.length === 0) {
console.log('処理対象の商品コードがありません');
return;
}

// バッチ処理で在庫情報を取得・更新
let totalUpdated = 0;
let totalErrors = 0;

for (let i = 0; i < goodsCodeList.length; i += batchSize) {
const batch = goodsCodeList.slice(i, i + batchSize);
console.log(`\n--- バッチ ${Math.floor(i / batchSize) + 1}: ${batch.length}件 ---`);

try {
// バッチで在庫情報を取得
const inventoryDataMap = getBatchInventoryData(batch, tokens);

// スプレッドシートを更新
for (const goodsCode of batch) {
const inventoryData = inventoryDataMap.get(goodsCode);
const rowIndex = rowIndexMap.get(goodsCode);

if (inventoryData && rowIndex) {
try {
updateRowWithInventoryData(sheet, rowIndex, inventoryData);
totalUpdated++;
console.log(` ✓ ${goodsCode}: 更新完了`);
} catch (error) {
console.error(` ✗ ${goodsCode}: 更新エラー - ${error.message}`);
totalErrors++;
}
} else {
console.log(` - ${goodsCode}: データなし`);
}
}

// バッチ間の待機(APIレート制限対策)
if (i + batchSize < goodsCodeList.length) {
console.log(`次のバッチまで ${apiWaitTime}ms 待機...`);
Utilities.sleep(apiWaitTime);
}

} catch (error) {
console.error(`バッチ処理エラー:`, error.message);
totalErrors += batch.length;
}
}

const endTime = new Date();
const duration = (endTime - startTime) / 1000;

console.log('\n=== 一括更新完了 ===');
console.log(`処理時間: ${duration.toFixed(1)}秒`);
console.log(`更新成功: ${totalUpdated}件`);
console.log(`エラー: ${totalErrors}件`);
console.log(`処理速度: ${(goodsCodeList.length / duration).toFixed(1)}件/秒`);

// 従来版との比較情報を表示
const conventionalTime = goodsCodeList.length * 2; // 従来版の推定時間(2秒/件)
const speedImprovement = conventionalTime / duration;
console.log(`\n--- 性能改善結果 ---`);
console.log(`従来版推定時間: ${conventionalTime.toFixed(1)}秒`);
console.log(`高速化倍率: ${speedImprovement.toFixed(1)}倍`);

} catch (error) {
console.error('一括更新エラー:', error.message);
throw error;
}
}

/**
* バッチで在庫情報を取得
* @param {string[]} goodsCodeList - 商品コードの配列
* @param {Object} tokens - アクセストークンとリフレッシュトークン
* @returns {Map} 商品コード → 在庫情報のマップ
*/
function getBatchInventoryData(goodsCodeList, tokens) {
const inventoryDataMap = new Map();

try {
console.log(` 商品マスタ一括検索: ${goodsCodeList.length}件`);

// ステップ1: 商品マスタAPIで複数商品を一括検索
const goodsDataMap = getBatchGoodsData(goodsCodeList, tokens);
console.log(` 商品マスタ取得完了: ${goodsDataMap.size}件`);

if (goodsDataMap.size === 0) {
console.log(' 商品が見つかりませんでした');
return inventoryDataMap;
}

// ステップ2: 在庫マスタAPIで複数商品の在庫を一括取得
console.log(` 在庫マスタ一括検索: ${goodsDataMap.size}件`);
const stockDataMap = getBatchStockData(Array.from(goodsDataMap.keys()), tokens);
console.log(` 在庫マスタ取得完了: ${stockDataMap.size}件`);

// ステップ3: 商品情報と在庫情報を結合
for (const [goodsCode, goodsData] of goodsDataMap) {
const stockData = stockDataMap.get(goodsCode);

const completeInventoryData = {
goods_id: goodsData.goods_id,
goods_name: goodsData.goods_name,
stock_quantity: stockData ? parseInt(stockData.stock_quantity) || 0 : parseInt(goodsData.stock_quantity) || 0,
stock_allocated_quantity: stockData ? parseInt(stockData.stock_allocation_quantity) || 0 : 0,
stock_free_quantity: stockData ? parseInt(stockData.stock_free_quantity) || 0 : 0,
stock_defective_quantity: stockData ? parseInt(stockData.stock_defective_quantity) || 0 : 0,
stock_advance_order_quantity: stockData ? parseInt(stockData.stock_advance_order_quantity) || 0 : 0,
stock_advance_order_allocation_quantity: stockData ? parseInt(stockData.stock_advance_order_allocation_quantity) || 0 : 0,
stock_advance_order_free_quantity: stockData ? parseInt(stockData.stock_advance_order_free_quantity) || 0 : 0,
stock_remaining_order_quantity: stockData ? parseInt(stockData.stock_remaining_order_quantity) || 0 : 0,
stock_out_quantity: stockData ? parseInt(stockData.stock_out_quantity) || 0 : 0
};

inventoryDataMap.set(goodsCode, completeInventoryData);
}

console.log(` 結合完了: ${inventoryDataMap.size}件`);
return inventoryDataMap;

} catch (error) {
console.error(`バッチ在庫取得エラー:`, error.message);
return inventoryDataMap;
}
}

/**
* 複数商品の基本情報を一括取得
* @param {string[]} goodsCodeList - 商品コードの配列
* @param {Object} tokens - トークン情報
* @returns {Map} 商品コード → 商品情報のマップ
*/
function getBatchGoodsData(goodsCodeList, tokens) {
const url = `${NE_API_URL}/api_v1_master_goods/search`;

// スクリプトプロパティからバッチサイズを取得
const properties = PropertiesService.getScriptProperties();
const batchSize = parseInt(properties.getProperty('BATCH_SIZE')) || 100;

// 複数の商品IDを検索条件に設定
const goodsIdCondition = goodsCodeList.join(',');

const payload = {
'access_token': tokens.accessToken,
'refresh_token': tokens.refreshToken,
'goods_id-in': goodsIdCondition, // IN条件で複数商品を一括検索
'fields': 'goods_id,goods_name,stock_quantity',
'limit': batchSize.toString() // 取得件数制限
};

const options = {
'method': 'POST',
'headers': {
'Content-Type': 'application/x-www-form-urlencoded'
},
'payload': Object.keys(payload).map(key =>
encodeURIComponent(key) + '=' + encodeURIComponent(payload[key])
).join('&')
};

const goodsDataMap = new Map();

try {
const response = UrlFetchApp.fetch(url, options);
const responseText = response.getContentText();
const responseData = JSON.parse(responseText);

console.log(` 商品マスタAPI応答: result=${responseData.result}, count=${responseData.count || 0}`);

// トークンが更新された場合は保存
if (responseData.access_token && responseData.refresh_token) {
updateStoredTokens(responseData.access_token, responseData.refresh_token);
// トークンを更新
tokens.accessToken = responseData.access_token;
tokens.refreshToken = responseData.refresh_token;
}

if (responseData.result === 'success' && responseData.data) {
responseData.data.forEach(goodsData => {
goodsDataMap.set(goodsData.goods_id, {
goods_id: goodsData.goods_id,
goods_name: goodsData.goods_name,
stock_quantity: goodsData.stock_quantity
});
});

console.log(` API応答: ${responseData.data.length}件取得`);
} else {
console.error(` 商品マスタAPI エラー:`, responseData.message || 'Unknown error');
}

return goodsDataMap;

} catch (error) {
console.error(`商品マスタ一括取得エラー:`, error.message);
return goodsDataMap;
}
}

/**
* 複数商品の在庫情報を一括取得
* @param {string[]} goodsCodeList - 商品コードの配列
* @param {Object} tokens - トークン情報
* @returns {Map} 商品コード → 在庫情報のマップ
*/
function getBatchStockData(goodsCodeList, tokens) {
const url = `${NE_API_URL}/api_v1_master_stock/search`;

// スクリプトプロパティからバッチサイズを取得
const properties = PropertiesService.getScriptProperties();
const batchSize = parseInt(properties.getProperty('BATCH_SIZE')) || 100;

// 複数の商品IDを検索条件に設定
const goodsIdCondition = goodsCodeList.join(',');

const payload = {
'access_token': tokens.accessToken,
'refresh_token': tokens.refreshToken,
'stock_goods_id-in': goodsIdCondition, // IN条件で複数商品の在庫を一括検索
'fields': 'stock_goods_id,stock_quantity,stock_allocation_quantity,stock_defective_quantity,stock_remaining_order_quantity,stock_out_quantity,stock_free_quantity,stock_advance_order_quantity,stock_advance_order_allocation_quantity,stock_advance_order_free_quantity',
'limit': batchSize.toString()
};

const options = {
'method': 'POST',
'headers': {
'Content-Type': 'application/x-www-form-urlencoded'
},
'payload': Object.keys(payload).map(key =>
encodeURIComponent(key) + '=' + encodeURIComponent(payload[key])
).join('&')
};

const stockDataMap = new Map();

try {
const response = UrlFetchApp.fetch(url, options);
const responseText = response.getContentText();
const responseData = JSON.parse(responseText);

console.log(` 在庫マスタAPI応答: result=${responseData.result}, count=${responseData.count || 0}`);

// トークンが更新された場合は保存
if (responseData.access_token && responseData.refresh_token) {
updateStoredTokens(responseData.access_token, responseData.refresh_token);
// トークンを更新
tokens.accessToken = responseData.access_token;
tokens.refreshToken = responseData.refresh_token;
}

if (responseData.result === 'success' && responseData.data) {
responseData.data.forEach(stockData => {
stockDataMap.set(stockData.stock_goods_id, stockData);
});

console.log(` API応答: ${responseData.data.length}件取得`);
} else {
console.error(` 在庫マスタAPI エラー:`, responseData.message || 'Unknown error');
}

return stockDataMap;

} catch (error) {
console.error(`在庫マスタ一括取得エラー:`, error.message);
return stockDataMap;
}
}

/**
* 保存されたトークンを取得(既存関数)
*/
function getStoredTokens() {
const properties = PropertiesService.getScriptProperties();
const accessToken = properties.getProperty('ACCESS_TOKEN');
const refreshToken = properties.getProperty('REFRESH_TOKEN');

if (!accessToken || !refreshToken) {
throw new Error('アクセストークンが見つかりません。先に認証を完了してください。');
}

return {
accessToken,
refreshToken
};
}

/**
* スプレッドシートの行を在庫データで更新(既存関数)
*/
function updateRowWithInventoryData(sheet, rowIndex, inventoryData) {
const updateValues = [
inventoryData.stock_quantity || 0,
inventoryData.stock_allocated_quantity || 0,
inventoryData.stock_free_quantity || 0,
inventoryData.stock_advance_order_quantity || 0,
inventoryData.stock_advance_order_allocation_quantity || 0,
inventoryData.stock_advance_order_free_quantity || 0,
inventoryData.stock_defective_quantity || 0,
inventoryData.stock_remaining_order_quantity || 0,
inventoryData.stock_out_quantity || 0
];

const range = sheet.getRange(rowIndex, COLUMNS.STOCK_QTY + 1, 1, updateValues.length);
range.setValues([updateValues]);
}

/**
* トークンを更新保存(既存関数)
*/
function updateStoredTokens(accessToken, refreshToken) {
const properties = PropertiesService.getScriptProperties();
properties.setProperties({
'ACCESS_TOKEN': accessToken,
'REFRESH_TOKEN': refreshToken,
'TOKEN_UPDATED_AT': new Date().getTime().toString()
});
console.log(' トークンを更新しました');
}

/**
* テスト用:小規模バッチでの動作確認
* @param {number} maxItems - テスト対象の最大商品数(デフォルト: 10)
*/
function testBatchProcessing(maxItems = 10) {
try {
console.log(`=== バッチ処理テスト(最大${maxItems}件) ===`);

// スクリプトプロパティから設定値を取得
const properties = PropertiesService.getScriptProperties();
const spreadsheetId = properties.getProperty('SPREADSHEET_ID');
const sheetName = properties.getProperty('SHEET_NAME');

if (!spreadsheetId || !sheetName) {
throw new Error('SPREADSHEET_IDまたはSHEET_NAMEがスクリプトプロパティに設定されていません。');
}

// スプレッドシートから商品コードを取得
const spreadsheet = SpreadsheetApp.openById(spreadsheetId);
const sheet = spreadsheet.getSheetByName(sheetName);
const lastRow = sheet.getLastRow();

if (lastRow <= 1) {
console.log('テスト用データが存在しません');
return;
}

const dataRange = sheet.getRange(2, 1, Math.min(maxItems, lastRow - 1), 1);
const values = dataRange.getValues();
const goodsCodeList = values
.map(row => row[0])
.filter(code => code && code.toString().trim())
.slice(0, maxItems);

console.log(`テスト対象商品コード: ${goodsCodeList.join(', ')}`);

const tokens = getStoredTokens();

// バッチで在庫情報を取得
const startTime = new Date();
const inventoryDataMap = getBatchInventoryData(goodsCodeList, tokens);
const endTime = new Date();
const duration = (endTime - startTime) / 1000;

console.log(`\n=== テスト結果 ===`);
console.log(`処理時間: ${duration.toFixed(1)}秒`);
console.log(`取得件数: ${inventoryDataMap.size}件`);
console.log(`処理速度: ${(goodsCodeList.length / duration).toFixed(1)}件/秒`);

// 取得したデータの内容を表示
for (const [goodsCode, data] of inventoryDataMap) {
console.log(`${goodsCode}: 在庫${data.stock_quantity} 引当${data.stock_allocated_quantity} フリー${data.stock_free_quantity}`);
}

} catch (error) {
console.error('バッチテストエラー:', error.message);
throw error;
}
}

/**
* パフォーマンス比較用:従来版と一括版の処理時間を比較
* @param {number} sampleSize - 比較対象のサンプル数(デフォルト: 10)
*/
function comparePerformance(sampleSize = 10) {
console.log(`=== パフォーマンス比較テスト(${sampleSize}件) ===`);

// スクリプトプロパティから設定値を取得
const properties = PropertiesService.getScriptProperties();
const spreadsheetId = properties.getProperty('SPREADSHEET_ID');
const sheetName = properties.getProperty('SHEET_NAME');

if (!spreadsheetId || !sheetName) {
throw new Error('SPREADSHEET_IDまたはSHEET_NAMEがスクリプトプロパティに設定されていません。');
}

// スプレッドシートから商品コードを取得
const spreadsheet = SpreadsheetApp.openById(spreadsheetId);
const sheet = spreadsheet.getSheetByName(sheetName);
const lastRow = sheet.getLastRow();

if (lastRow <= 1) {
console.log('テスト用データが存在しません');
return;
}

const dataRange = sheet.getRange(2, 1, Math.min(sampleSize, lastRow - 1), 1);
const values = dataRange.getValues();
const goodsCodeList = values
.map(row => row[0])
.filter(code => code && code.toString().trim())
.slice(0, sampleSize);

console.log(`比較対象商品コード: ${goodsCodeList.join(', ')}`);

const tokens = getStoredTokens();

// 従来版の推定時間(実際には実行しない)
const conventionalEstimatedTime = goodsCodeList.length * 2; // 2秒/件

// 一括版の実際の処理時間
console.log('\n一括版実行中...');
const startTime = new Date();
const inventoryDataMap = getBatchInventoryData(goodsCodeList, tokens);
const endTime = new Date();
const batchTime = (endTime - startTime) / 1000;

// 結果比較
const speedImprovement = conventionalEstimatedTime / batchTime;

console.log('\n=== 性能比較結果 ===');
console.log(`従来版推定時間: ${conventionalEstimatedTime.toFixed(1)}秒(${sampleSize} × 2秒/件)`);
console.log(`一括版実際時間: ${batchTime.toFixed(1)}秒`);
console.log(`高速化倍率: ${speedImprovement.toFixed(1)}倍`);
console.log(`取得成功率: ${(inventoryDataMap.size / goodsCodeList.length * 100).toFixed(1)}%`);

// 数千件での推定効果
const estimatedFor1000 = {
conventional: 1000 * 2 / 60, // 分
batch: 1000 / goodsCodeList.length * batchTime / 60 // 分
};

console.log('\n=== 1000件処理時の推定時間 ===');
console.log(`従来版: ${estimatedFor1000.conventional.toFixed(1)}分`);
console.log(`一括版: ${estimatedFor1000.batch.toFixed(1)}分`);
console.log(`時間短縮: ${(estimatedFor1000.conventional - estimatedFor1000.batch).toFixed(1)}分`);
}

/**
* 使用方法ガイド
*/
function showBatchUsageGuide() {
console.log('=== 一括処理版 使用方法ガイド ===');
console.log('');
console.log('【主要関数】');
console.log('1. updateInventoryDataBatch()');
console.log(' - 全商品の在庫情報を一括処理で更新');
console.log(' - 100件ずつのバッチで自動分割処理');
console.log(' - 従来版より大幅に高速化');
console.log('');
console.log('2. testBatchProcessing(件数)');
console.log(' - 小規模テスト用(デフォルト10件)');
console.log(' - 例: testBatchProcessing(5)');
console.log('');
console.log('3. comparePerformance(件数)');
console.log(' - 従来版との性能比較テスト');
console.log(' - 例: comparePerformance(20)');
console.log('');
console.log('【期待される改善効果】');
console.log('- APIコール数: 1/50~1/100に削減');
console.log('- 処理速度: 10~50倍の高速化');
console.log('- 実行時間制限: 数千件でも制限内で完了');
console.log('- API制限: レート制限に引っかかりにくい');
console.log('');
console.log('【推奨実行手順】');
console.log('1. testBatchProcessing(10) で動作確認');
console.log('2. comparePerformance(20) で性能確認');
console.log('3. updateInventoryDataBatch() で全件更新');
console.log('');
console.log('【設定変更可能項目】');
console.log('- BATCH_SIZE: バッチサイズ(現在100件)');
console.log('- API_WAIT_TIME: API間隔(現在500ms)');
}
-------------------------------------------
updateInventoryDataBatchを実行した結果のログ

16:47:53 お知らせ 実行開始
16:47:43 情報 === 在庫情報一括更新開始 ===
16:47:44 情報 処理対象: 3106行
16:47:44 情報 有効な商品コード: 3106件
16:47:44 情報
--- バッチ 1: 100件 ---
16:47:44 情報 商品マスタ一括検索: 100件
16:47:45 情報 商品マスタAPI応答: result=success, count=100
16:47:45 情報 トークンを更新しました
16:47:45 情報 API応答: 100件取得
16:47:45 情報 商品マスタ取得完了: 100件
16:47:45 情報 在庫マスタ一括検索: 100件
16:47:46 情報 在庫マスタAPI応答: result=success, count=100
16:47:46 情報 トークンを更新しました
16:47:46 情報 API応答: 100件取得
16:47:46 情報 在庫マスタ取得完了: 100件
16:47:46 情報 結合完了: 100件
中略
16:48:47 情報
=== 一括更新完了 ===
16:48:47 情報 処理時間: 64.5秒
16:48:47 情報 更新成功: 3106件
16:48:47 情報 エラー: 0件
16:48:47 情報 処理速度: 48.1件/秒
16:48:47 情報
--- 性能改善結果 ---
16:48:47 情報 従来版推定時間: 6212.0秒
16:48:47 情報 高速化倍率: 96.3倍
16:48:59 お知らせ 実行完了

これまでと比べて大幅に短縮しました。
ありがとうございます。

をClaudeに伝えると・・・
-------------------------------------------
素晴らしい結果ですね!一括処理版が期待通りの性能を発揮していることが確認できました。

**改善結果の詳細:**

| 項目 | 従来版(推定) | 一括処理版(実測) | 改善効果 |
|------|---------------|------------------|----------|
| **処理時間** | 6,212秒(約1時間43分) | 64.5秒(約1分) | **96.3倍高速化** |
| **処理速度** | 0.5件/秒 | 48.1件/秒 | **96倍向上** |
| **成功率** | - | 100%(3,106件全て成功) | **完璧** |
| **エラー数** | - | 0件 | **安定動作** |

**技術的な改善点が効果を発揮:**

1. **APIコール数の削減**:
- 従来版:3,106 × 2 = 6,212回のAPIコール
- 一括版:約62回のAPIコール(100件ずつ31バッチ × 2API)
- **99%削減**

2. **バッチ処理の効率性**:
- ネットワーク遅延の影響を最小化
- APIレート制限を回避
- メモリ効率の良いデータ処理

3. **Google Apps Scriptの実行時間制限対策**:
- 従来版では制限(6分)を大幅に超過
- 一括版では制限内(64.5秒)で完了

**今後の運用について:**

この一括処理版により、日常的な在庫情報更新が非常に効率的になりました。3,000件超のデータでも1分程度で完了するため、定期実行やリアルタイム更新にも適用できます。

N88-BASICから始まられたプログラミングの基礎が、このような現代的な最適化にも活かされていますね。バッチ処理の概念は、昔からプログラミングの重要な技術の一つです。

何かご質問や、さらなる改善のご要望があれば、お気軽にお声がけください!
-------------------------------------------
途中GPTでショートカットした時間で言えば、
午後の1時間でここまで来ました。
因みに上のスクリプトは時間をかけてClaudeでコーディングしてくれた内容です。

ログの見積もりと異なりますが、
午前中までは3000行の取得が3600秒(60分=1時間)程必要だったのに対して、
午後の1時間だけで3000行の取得がわずか64.5秒で完了しました(・・;)

これは、TepsやYoomのログを見てきた私からすると信じられない速度です。

予想の斜め上を行く結果となりました(・・;)

在庫情報取得が48.1件/秒とは・・・

1回のAPIコールで100件の在庫情報が取得できるとは・・・

3000行の取得が60秒ほどで実行可能になるということは
更新頻度をもっと高めることが出来るということになります。
-------------------------------------------
ここまで出来たのは先週の木曜日の話です。
コーディングは複数のAIとGitHubのブランチを利用することで、
APIコール数を半分にすることまで出来るようになりました。

また、1回のAPIコールで100件の在庫情報取得というのに疑問を持って・・・

今日はこのくらいにしておきましょうかね^^;
Posted at 2025/09/12 23:00:57 | コメント(0) | トラックバック(0) | 日記

プロフィール

「アルテシマが激成長してきました。 http://cvw.jp/b/11052/48659541/
何シテル?   09/16 23:49
2025/06/23追記 ヘッダー画像について興味をお持ちの方もいらっしゃると思いますが、こちらは2025/06/21に香川県で開催されました、GAZOO 愛...
みんカラ新規会員登録

ユーザー内検索

<< 2025/9 >>

  1 2 3 4 5 6
7 8 9 10 11 1213
14 15 1617181920
21222324252627
282930    

リンク・クリップ

GAZOO 愛車広場 出張取材会 in 香川 満を持してチェイサーの記事が公開されました(^^) 
カテゴリ:その他(カテゴリ未設定)
2025/08/22 08:26:45
電費履歴リセット 
カテゴリ:その他(カテゴリ未設定)
2024/10/12 07:34:32
裏ワザでウィンドウズ11へ^^笑)。 
カテゴリ:その他(カテゴリ未設定)
2024/01/27 14:12:45

愛車一覧

トヨタ チェイサー GR Chaser TourerV TRD sports version (トヨタ チェイサー)
2025/06/21 GAZOO様の出張取材会で取材を頂きました。 https://ga ...
日産 リーフ 日産 リーフ
JZX100 Chaser 1JZ-GTE 2500cc ターボを所有しつつのセカンドカ ...
ホンダ アコード ホンダ アコード
私のではなく弟の車です。 色はアークティックブルーパールのEuro-Rです。 購入してし ...

過去のブログ

2025年
01月02月03月04月05月06月
07月08月09月10月11月12月
2024年
01月02月03月04月05月06月
07月08月09月10月11月12月
2023年
01月02月03月04月05月06月
07月08月09月10月11月12月
2022年
01月02月03月04月05月06月
07月08月09月10月11月12月
2021年
01月02月03月04月05月06月
07月08月09月10月11月12月
2020年
01月02月03月04月05月06月
07月08月09月10月11月12月
2019年
01月02月03月04月05月06月
07月08月09月10月11月12月
2018年
01月02月03月04月05月06月
07月08月09月10月11月12月
2017年
01月02月03月04月05月06月
07月08月09月10月11月12月
2016年
01月02月03月04月05月06月
07月08月09月10月11月12月
2015年
01月02月03月04月05月06月
07月08月09月10月11月12月
2014年
01月02月03月04月05月06月
07月08月09月10月11月12月
2013年
01月02月03月04月05月06月
07月08月09月10月11月12月
2012年
01月02月03月04月05月06月
07月08月09月10月11月12月
2011年
01月02月03月04月05月06月
07月08月09月10月11月12月
2010年
01月02月03月04月05月06月
07月08月09月10月11月12月
2007年
01月02月03月04月05月06月
07月08月09月10月11月12月
2006年
01月02月03月04月05月06月
07月08月09月10月11月12月
2005年
01月02月03月04月05月06月
07月08月09月10月11月12月
ヘルプ利用規約サイトマップ
© LY Corporation