<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on GITY Blog</title><link>https://blog.gity.co.jp/post/</link><description>Recent content in Posts on GITY Blog</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><copyright>CATENAS inc.</copyright><lastBuildDate>Mon, 22 Sep 2025 04:24:24 +0900</lastBuildDate><atom:link href="https://blog.gity.co.jp/post/index.xml" rel="self" type="application/rss+xml"/><item><title>地域創⽣・社会課題解決 AI プログラミング コンテストに参加してきました！</title><link>https://blog.gity.co.jp/posts/20250922/awscontest/</link><pubDate>Mon, 22 Sep 2025 04:24:24 +0900</pubDate><guid>https://blog.gity.co.jp/posts/20250922/awscontest/</guid><description>&lt;img src="https://blog.gity.co.jp/posts/20250922/awscontest/images/IMG_1667.jpg" alt="Featured image of post 地域創⽣・社会課題解決 AI プログラミング コンテストに参加してきました！" />&lt;h2 id="コンテストについて">コンテストについて
&lt;/h2>&lt;p>この度私たちは&lt;a class="link" href="https://aws.amazon.com/jp/government-education/worldwide/japan/nationwide-2025/" target="_blank" rel="noopener"
>AWSデジタル社会実現ツアー2025&lt;/a>に参加してきました。このツアーは、地域社会の「DX」を加速し、持続可能な地域創生を実現することを目的としています。AWS主催の元、「産・官・学・金」がパネリストとして、参加し、ビジョンや、実績の共有、学生のプロダクトへのフィードバックなどを行いました。&lt;/p>
&lt;p>私たち3人はこのツアー内で開催されたコンテストにプレゼンテーターとして参加し、多くのことを学んできました。各々の学びと成果を皆さんにもお伝えできれば幸いです。&lt;/p>
&lt;h2 id="初めに">初めに
&lt;/h2>&lt;p>昨今、巷では地域創生が求められており、国や地方自治体はDX推進や技術発展のための「場」を作ることに注力しています。例えば経済産業省からは&lt;a class="link" href="https://www.ipa.go.jp/jinzai/mitou/about.html" target="_blank" rel="noopener"
>未踏&lt;/a>や&lt;a class="link" href="https://www.meti.go.jp/policy/mono_info_service/geniac/index.html" target="_blank" rel="noopener"
>GENIAC&lt;/a>、&lt;a class="link" href="https://mitouteki.jp/" target="_blank" rel="noopener"
>AKATSUKIプロジェクト&lt;/a>といった事業が行われており、コミュニティの形成や人材育成が行われています。&lt;/p>
&lt;p>地方自治体や地場企業も同様にコミュニティの形成やコンテストの開催等の積極的な活動が行われている他、金融機関によるベンチャーキャピタルの立ち上げなど、地域の若手人材や起業家の育成も行われています。&lt;/p>
&lt;p>それらの活動が実を結び、実際に様々なコミュニティが形成され情報共有やリソースの循環を通して熱意ある人々が様々なイノベーションを起こそうとしています。&lt;/p>
&lt;h2 id="知見の広がりと学び">知見の広がりと学び
&lt;/h2>&lt;h3 id="日本各地の取り組み">日本各地の取り組み
&lt;/h3>&lt;p>日本各地で、様々なコミュニティが創生されていることを知りました。例えば新潟では学生が主体となって社会課題解決のためのイベントや活動を行う「&lt;a class="link" href="https://ninno-kaigi.com/" target="_blank" rel="noopener"
>NINNO3（ニーノスリー）&lt;/a>」の紹介がありました。北九州の「&lt;a class="link" href="https://compass-kokura.com/" target="_blank" rel="noopener"
>COMPASS小倉&lt;/a>」は市内総生産4兆円をビジョンに掲げ、創業交流会やイベントを通じて地域への思いを持った起業家を支援し、人々をつなぐ場となっています。&lt;/p>
&lt;p>経済力のある地域では地方とはまた異なった様子を見ることができました。大阪市の&lt;a class="link" href="https://www.quintbridge.jp/" target="_blank" rel="noopener"
>QUINTBRIDGE&lt;/a>では企業パートナーと共に「学ぶ」「つながる」「共創する」を掲げ、人々の交流と挑戦の場となっています。年間700以上のイベントが行われ、日々交流しています。QUINTBRIDGEには活気ある人々が集まり、&amp;ldquo;共創プロジェクト&amp;quot;を通して課題解決を試みる挑戦的な場所でした。&lt;/p>
&lt;p>これらの場所のすべてに共通するのはGITYと非常に似た特徴を持っているということです。学びを通して成長していくコミュニティを形成する機能を持った場所であることです。人と人がつながることで新たな交流が生まれ、宝石の原石であるユニークなアイデアは交流を通して磨かれます。&lt;/p>
&lt;p>日本各地でこういった場所が誕生しているということへ驚きと機会提供のありがたさを実感しました。&lt;/p>
&lt;p>政府による事業も知ることができました。経済産業省は&lt;a class="link" href="https://www.meti.go.jp/policy/mono_info_service/geniac/index.html" target="_blank" rel="noopener"
>GENIAC&lt;/a>というAI開発・発展のためのコミュニティの形成を試みています。AI開発者や企業の情報交換やフィードバックが行われています。学生向けのオンラインコミュニティ形成の構想もあり、AI開発コミュニティの裾野をより若い世代へと広げたいとのことでした。&lt;/p>
&lt;p>&lt;a class="link" href="https://www.quintbridge.jp/" target="_blank" rel="noopener"
>AKATUKIプロジェクト&lt;/a>では、地方でのトップIT人材、企業家の人材発掘を進めるために、プロジェクトを遂行するための環境と、能力のある若手人材への投資をしてくれる環境がありました。北九州では、AKATUKIプロジェクトに採択されている学生がいて、AIの力を活用し、地域文化への理解促進と、持続可能な観光体験を創出するための観光アプリを発表しました。技術力の高さと、着眼点に驚きました。&lt;/p>
&lt;p>&lt;img src="https://blog.gity.co.jp/posts/20250922/awscontest/images/IMG_1513.jpg"
width="4032"
height="3024"
srcset="https://blog.gity.co.jp/posts/20250922/awscontest/images/IMG_1513_hu17216512974723324034.jpg 480w, https://blog.gity.co.jp/posts/20250922/awscontest/images/IMG_1513_hu8245087731419061416.jpg 1024w"
loading="lazy"
alt="Startup loft"
class="gallery-image"
data-flex-grow="133"
data-flex-basis="320px"
>
/
AWSでは、スタートアップ支援を行っており、AWS japanの本社内には、&lt;a class="link" href="https://aws.amazon.com/startups/lp/aws-startup-loft-tokyo?lang=ja" target="_blank" rel="noopener"
>AWS Startup Loft&lt;/a>を設置していました。新しいものを生み出そうとする人々が集まり、刺激し合い、新たなものが生まれる場所でした。概要と利用方法は、&lt;a class="link" href="https://aws.amazon.com/startups/lp/aws-startup-loft-tokyo?lang=ja" target="_blank" rel="noopener"
>こちら&lt;/a>です。&lt;/p>
&lt;h3 id="参加してみての学び">参加してみての学び
&lt;/h3>&lt;p>次に今回のコンテスト最大の学びは、「熱意と責任感をもって挑戦することが大切」だということです。&lt;/p>
&lt;p>良いものを作るには、熱意と責任感が大切だと感じました。これらがあれば、困難な壁を越えたり、モチベーションを維持して継続したり、最後の踏ん張りがきくようになると感じました。
もしこれらが欠けていると、中途半端なものしか作ることができず、良いものは作れないと思いました。&lt;/p>
&lt;p>また、自分は臆病な性格なので、少しハードルが高くても、飛び込む勇気も必要だと気づかされました。&lt;/p>
&lt;p>コンテスト内での優勝者は皆、熱意をもって作ったプロダクトとプレゼンで、優勝していました。
そして、自分のプロダクトに愛着と誇りを持っているひとたちだと感じます。&lt;/p>
&lt;p>小林大起&lt;/p>
&lt;h2 id="発表を通じて見えた外に出す価値">発表を通じて見えた&lt;strong>外に出す価値&lt;/strong>
&lt;/h2>&lt;p>私たちの作品は、新潟大会で最優秀賞を受けたことをきっかけに、「基準作品」として各地で紹介されるようになりました。これまで6会場では技術担当として裏方に回り、質問対応を担ってきましたが、AWSの滝沢さんに「せっかくだからチャレンジしてみない？」と声をかけてもらい、北九州大会では初めて発表者として登壇することに。&lt;/p>
&lt;p>実際にステージに立つと、必要以上に緊張し、人前に出ると極端に硬くなる性格がそのまま出てしまいました。プレゼンの最中はカンペから目を離せず、言葉も思うように出てこない。正直、心の中では「失敗だ」とつぶやいていました。&lt;/p>
&lt;p>ところが終わってみると、審査員や参加者からは「熱量がすごく伝わった」との声。自分では全くうまくいかなかったと思っていたのに、外からの印象はまるで違っていたのです。このギャップこそが大きな発見でした。&lt;/p>
&lt;p>さらに、技術的な質問に加えて「このプロダクトをぜひ使いたい」という声や、導入の相談まで寄せられました。単なる説明の場ではなく、プロダクトが“次の現場”とつながる出会いの場になっていたのだと気づかされました。&lt;/p>
&lt;p>今回の経験で強く感じたのは、プロダクトは公に出してこそ真価を発揮するということ。完璧な発表でなくても、外に出すことで思わぬフィードバックや新しい縁が生まれること。緊張で言葉が詰まっても、それでも伝わるものがあるということです。&lt;/p>
&lt;p>これからも発表や公開の機会を積極的に持ち、外からの声を取り入れながらプロダクトを磨き上げていきたい。外に出す勇気が、次の成長を引き寄せてくれると確信しています。&lt;/p>
&lt;p>山田陽仁&lt;/p>
&lt;h2 id="awsコンテストを通して気づいた伝える力">AWSコンテストを通して気づいた「伝える力」
&lt;/h2>&lt;p>今回、コンテストに参加して強く実感したのは「どれだけ良い内容でも、伝え方次第で人の受け取り方は大きく変わる」ということでした。&lt;br>
私はまだまだ拙く、プレゼンに自信があるわけではありません。ですが、新潟・名古屋・大阪・東京・仙台の5回のプレゼンを重ねる中でいただいた温かいフィードバックを通じて、「伝えること」の意味を少しずつ掴んでいけた気がします。&lt;/p>
&lt;h3 id="最初のプレゼンで感じたこと">最初のプレゼンで感じたこと
&lt;/h3>&lt;p>最初のプレゼンで学んだのは、ただ事実を説明するだけではなく「ストーリー」があることで相手の心に届く、ということです。なぜその取り組みをしたのか、どんな思いを込めたのか。その背景を語ることで、内容以上に想いが伝わるのだと実感しました。&lt;/p>
&lt;h3 id="フィードバックに支えられて">フィードバックに支えられて
&lt;/h3>&lt;p>その後のプレゼンでは、ありがたいことに「自信を持って話せているのが良い」と言っていただけたり、回を重ねるごとに一緒に回ってくださった運営の方から「すごく上達した」と声をかけてもらえました。&lt;br>
そうした言葉は大きな励みになり、「まだまだ」な私でも、少しずつ前に進めているのだと実感できました。&lt;/p>
&lt;p>（AWSの方に「緊張は誰でもするので、優しそうな人を一人見つけて、その人を見て話して、その人が頷いたら次は違う人を見るというのを繰り返すと、緊張が多少は解れますよ😊」とアドバイスをいただいて、とても安心しました笑）&lt;/p>
&lt;h3 id="5回を通じての気づき">5回を通じての気づき
&lt;/h3>&lt;p>5回のプレゼンを通じて分かったのは、プレゼンは「完璧に説明する場」ではなく「想いを届ける場」だということです。&lt;/p>
&lt;ul>
&lt;li>ストーリーが人を動かし、&lt;/li>
&lt;li>言葉が理解を助け、&lt;/li>
&lt;li>熱量が共感を生む。&lt;/li>
&lt;/ul>
&lt;p>私はまだ道半ばですが、この経験を通して「伝えること」そのものが、プロダクト開発と同じくらい大事な力だと気づきました。これからもいただいたフィードバックを大切にしながら、少しずつ成長していきたいと思います。&lt;/p>
&lt;p>真庭詩音&lt;/p>
&lt;h2 id="おわりに">おわりに
&lt;/h2>&lt;p>今回の発表でいろいろとご尽力いただいた皆様、誠にありがとうございます。多くの学びと、経験をすることができ、ものすごく勉強になりました。
GITYの皆様、今後ともよろしくお願いいたします。&lt;/p>
&lt;p>&lt;img src="https://blog.gity.co.jp/posts/20250922/awscontest/images/IMG_1510.jpg"
width="4032"
height="3024"
srcset="https://blog.gity.co.jp/posts/20250922/awscontest/images/IMG_1510_hu12081566574770170909.jpg 480w, https://blog.gity.co.jp/posts/20250922/awscontest/images/IMG_1510_hu10629249733004164339.jpg 1024w"
loading="lazy"
alt="装飾されたユニコーンの写真"
class="gallery-image"
data-flex-grow="133"
data-flex-basis="320px"
>&lt;/p></description></item><item><title>来たるべきAI地方幕府時代に向けて畑を耕す</title><link>https://blog.gity.co.jp/posts/20250618/ai-farming/</link><pubDate>Wed, 18 Jun 2025 16:09:20 +0900</pubDate><guid>https://blog.gity.co.jp/posts/20250618/ai-farming/</guid><description>&lt;img src="https://blog.gity.co.jp/posts/20250618/ai-farming/thumb.jpg" alt="Featured image of post 来たるべきAI地方幕府時代に向けて畑を耕す" />&lt;h2 id="これはなに">これはなに
&lt;/h2>&lt;p>いま、クーデターがアツい。&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>ある技術書&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>によれば、統制の取れた実力組織と専門職、特に電気・情報系を用意し、電撃的に国家中枢とメディア設備を奪取すればよいらしい。コトが終わったら国家運営を実質的に担う官僚組織を懐柔することも忘れずに。ところで、GITYには専門職の豊富なリソースが揃っている。発達したAI技術は硬直した官僚機構よりも素晴らしい働きをするだろう。これは巨額の投資を受けるAIベンチャー企業のCEOたちの発言を引用するまでもなく明らかなことだ。&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup>&lt;strong>あとは実力だけ。&lt;/strong>&lt;/p>
&lt;h2 id="はじめに">はじめに
&lt;/h2>&lt;p>今、日本の食料安全保障は危機に瀕している。農家の平均年齢はおおよそ68歳であり&lt;sup id="fnref:4">&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref">4&lt;/a>&lt;/sup>、定年退職をきっかけにして就農した高齢者ですら、農家コミュニティの中では”ワカモン”として扱われる現状がある。従来的な農家の経営体には当然限界が来ており、農家の戸数は減少を続けている&lt;sup id="fnref:5">&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref">5&lt;/a>&lt;/sup>。とうちゃんが死んじまったから、もう体力が/腰が限界だから、トラクターが壊れたから、太陽が眩しかったから、離農した。&lt;br>
直近に起こったイベントに目を向けよう。ロシアのウクライナ侵攻以降、肥料価格は過去に例を見ないほど高騰した。農家はさらなる適正施肥を求められ、一層効率的な経営を求められている。&lt;sup id="fnref:6">&lt;a href="#fn:6" class="footnote-ref" role="doc-noteref">6&lt;/a>&lt;/sup>南海トラフ巨大地震の予測以降、米価の高止まりが続く。令和の米騒動とまで名前が付き、一躍巨大政局にまでなった。&lt;sup id="fnref:7">&lt;a href="#fn:7" class="footnote-ref" role="doc-noteref">7&lt;/a>&lt;/sup>&lt;br>
このような現状に対し、地方から食料安全保障の一翼を担おうという動きが生まれるのは当然だろう。とにかくカロリーベースだ！育てるのはイモ類！チャラチャラしたルッコラとかアイスプラントとか、そういうよくわからん草は育てん！&lt;/p>
&lt;h2 id="準備">準備
&lt;/h2>&lt;p>まずは土と苗を用意する。これは材料と設計図にあたる。土は植え付けのしばらく前までに施肥を行い、よく耕す。団粒構造を形成することが望ましいが、必須ではない。苗は種苗店に事前に注文しておく。必要なぶんだけを購入すること。苗は自然の中に普遍的に存在するから不要である&lt;sup id="fnref:8">&lt;a href="#fn:8" class="footnote-ref" role="doc-noteref">8&lt;/a>&lt;/sup>、という都合のいい話はない。&lt;br>
サツマイモの苗は茎の形で販売される。成長点が無事ならばとりあえずよいので、葉がしおれていても問題はない。買ってすぐ植え付けないならば、ビニール袋を掛けて蒸散を抑制し冷暗所に仮置きするのが良いだろう。&lt;/p>
&lt;p>&lt;img src="https://blog.gity.co.jp/posts/20250618/ai-farming/satsumaimo_seedling.jpg"
width="3072"
height="4080"
srcset="https://blog.gity.co.jp/posts/20250618/ai-farming/satsumaimo_seedling_hu16050898302902704141.jpg 480w, https://blog.gity.co.jp/posts/20250618/ai-farming/satsumaimo_seedling_hu13287405733086338071.jpg 1024w"
loading="lazy"
alt="サツマイモの苗はこのような形で提供される"
class="gallery-image"
data-flex-grow="75"
data-flex-basis="180px"
>&lt;/p>
&lt;p>畝の作成や植え付け時には特に理性が必要というわけでもない&lt;sup id="fnref:9">&lt;a href="#fn:9" class="footnote-ref" role="doc-noteref">9&lt;/a>&lt;/sup>ので、徹夜でぼけた頭でも十分作業可能だが、熱中症には十分注意するように。電解質と水分を準備しよう。どれだけ扱いにくいワーカーであっても、この炭素生命体を使うしかない……&lt;/p>
&lt;p>&lt;img src="https://blog.gity.co.jp/posts/20250618/ai-farming/carbon.jpg"
width="4096"
height="3072"
srcset="https://blog.gity.co.jp/posts/20250618/ai-farming/carbon_hu8397032006226059317.jpg 480w, https://blog.gity.co.jp/posts/20250618/ai-farming/carbon_hu11409920943788632668.jpg 1024w"
loading="lazy"
alt="この炭素生命体が畑を耕している"
class="gallery-image"
data-flex-grow="133"
data-flex-basis="320px"
>&lt;/p>
&lt;h2 id="畝の作成マルチング植え付け">畝の作成/マルチング/植え付け
&lt;/h2>&lt;p>畝を作成し、マルチで覆い、苗の植え付けを行う。この作業に熟練することによって、貴方がたは来たるべきAI地方幕府時代において然るべき地位を占めることができる。WIRED読者&lt;sup id="fnref:10">&lt;a href="#fn:10" class="footnote-ref" role="doc-noteref">10&lt;/a>&lt;/sup>がわかりやすいように言い換えよう。大半の労働者が失業する時代ーーホワイトカラーがAIエージェントに、ブルーカラーがヒューマノイドロボットに置き換えられ&lt;sup id="fnref:11">&lt;a href="#fn:11" class="footnote-ref" role="doc-noteref">11&lt;/a>&lt;/sup>、あらゆる機械がアデノシン三リン酸ではなくエレクトロンによって駆動するニューラルネットワークによって制御されるようになった時代&lt;sup id="fnref:12">&lt;a href="#fn:12" class="footnote-ref" role="doc-noteref">12&lt;/a>&lt;/sup>においても、おまんまの食い上げにはならない、ということだ。&lt;br>
具体的に考えていこう。高精度な位置情報サービスが広く提供され、自動運転技術も飛躍的に飛躍した現代において、重機を自動運転して省力化を図ることはごく自然な論理の帰結である。実際にダムの建設現場などにおいてすでに実用化されており&lt;sup id="fnref:13">&lt;a href="#fn:13" class="footnote-ref" role="doc-noteref">13&lt;/a>&lt;/sup>、当然農業分野においても実証実験が進んでいる。貴方の畑が十分に広ければ導入できるだろう。トラクターで外周を1周ぶんを人力で運転しなくてはならない&lt;sup id="fnref:14">&lt;a href="#fn:14" class="footnote-ref" role="doc-noteref">14&lt;/a>&lt;/sup>としても、労力を削減できるくらいに広い畑を持っているならば、だが。コストをペイできるかは更に別の問題だ。&lt;sup id="fnref:15">&lt;a href="#fn:15" class="footnote-ref" role="doc-noteref">15&lt;/a>&lt;/sup>&lt;/p>
&lt;p>&lt;img src="https://blog.gity.co.jp/posts/20250618/ai-farming/field.jpg"
width="3024"
height="4032"
srcset="https://blog.gity.co.jp/posts/20250618/ai-farming/field_hu4288445825261148132.jpg 480w, https://blog.gity.co.jp/posts/20250618/ai-farming/field_hu2329514485663442457.jpg 1024w"
loading="lazy"
alt="このような畑ではペイしない"
class="gallery-image"
data-flex-grow="75"
data-flex-basis="180px"
>&lt;/p>
&lt;p>汎用人型ロボットに畑を耕させる？何を言っているのかをまず理解しよう。これは不均一なソフトマテリアルの上を二足歩行する可動部の塊に防水防塵機能をつけて重量物を振り回させたいという要求だが、無理だ。デジタルツイン内で加速/並列してAIに制御を学習させるとか、もはやそういう次元の話ではない。無理なもんは無理にゃ！
農作業の具体的なやり方についてはここでは取り扱わない。YouTubeでも見とけ！&lt;sup id="fnref:16">&lt;a href="#fn:16" class="footnote-ref" role="doc-noteref">16&lt;/a>&lt;/sup>実際のところ、この手の作業はマニュアル化するには細かすぎる経験知が大量に必要なので見て覚えるのが一番早い。テキストですべてを説明してほしいオタクくんには難しいわけである。あなたを土に植えるわ。生まれ変わりなさい。&lt;sup id="fnref:17">&lt;a href="#fn:17" class="footnote-ref" role="doc-noteref">17&lt;/a>&lt;/sup>土を掘り上げて畝を作成する際に、高畝だからといって深く掘る必要はない。群馬県の大半の畑では改質されている層の下に固く締まった黒ボク土がある。&lt;sup id="fnref:18">&lt;a href="#fn:18" class="footnote-ref" role="doc-noteref">18&lt;/a>&lt;/sup>改質された層がない？それは可哀想に……リン酸を主体に施肥を行うのが良いだろう。&lt;/p>
&lt;h2 id="終わりに">終わりに
&lt;/h2>&lt;p>未曾有の少子化を背景に、人手不足が声高に叫ばれる昨今。地方自治体も当然その影響を受け、特に土木職の充足率は驚くほど低い&lt;sup id="fnref:19">&lt;a href="#fn:19" class="footnote-ref" role="doc-noteref">19&lt;/a>&lt;/sup>。民間セクタに目を向けても同様、土木の現場を担う人材の確保は年々難しくなっている。&lt;sup id="fnref:20">&lt;a href="#fn:20" class="footnote-ref" role="doc-noteref">20&lt;/a>&lt;/sup>世界的なインフレや通貨変動、自由貿易の後退などにより、施工費は前例のないレベルに高騰している。&lt;sup id="fnref:21">&lt;a href="#fn:21" class="footnote-ref" role="doc-noteref">21&lt;/a>&lt;/sup>これらの要因が合わさり、地方のインフラを維持することは難しくなりつつある。ひとたび臨界点に達すれば、放棄される地域も出てくるだろう……現段階の世論を参照しても、現実的な選択肢として受け入れられ、大きな反発もないことが予期できる&lt;sup id="fnref:22">&lt;a href="#fn:22" class="footnote-ref" role="doc-noteref">22&lt;/a>&lt;/sup>。スマートシティ構想は糖衣（ドラジェ）にすぎない。&lt;/p>
&lt;hr>
&lt;p>つまり：地方に中央政府の支配が及ばなくなる。あるいは、介入が遅れる。ここに我々の勝機がある。
インドア派のもやしっ子ばかりだが、エレベーターでなく階段を使う体力はある。&lt;sup id="fnref:23">&lt;a href="#fn:23" class="footnote-ref" role="doc-noteref">23&lt;/a>&lt;/sup>みな気のいい奴らばかりだ。牛乳も飲んでいる。&lt;sup id="fnref:24">&lt;a href="#fn:24" class="footnote-ref" role="doc-noteref">24&lt;/a>&lt;/sup>当然、年寄り連中に遅れを取るつもりはない。もはや事態は取り返しの付かないところまで来ているのだ。我々が、自らの手で地方を創生する。君たちにも畑を耕してもらうことになるだろう。&lt;/p>
&lt;h2 id="告知">告知
&lt;/h2>&lt;p>GITY農業はシリーズものです。次回作をお楽しみに！&lt;/p>
&lt;p>&lt;img src="https://blog.gity.co.jp/posts/20250618/ai-farming/satsumaimo_growing.jpg"
width="3024"
height="4032"
srcset="https://blog.gity.co.jp/posts/20250618/ai-farming/satsumaimo_growing_hu14902295658854673137.jpg 480w, https://blog.gity.co.jp/posts/20250618/ai-farming/satsumaimo_growing_hu2012538408527287592.jpg 1024w"
loading="lazy"
alt="サツマイモは順調に育っている"
class="gallery-image"
data-flex-grow="75"
data-flex-basis="180px"
>&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>諸説ある。 &lt;a class="link" href="https://jp.reuters.com/world/korea/TUWACF5E25K7TKFPRB4DGEV5MA-2025-04-14/" target="_blank" rel="noopener"
>https://jp.reuters.com/world/korea/TUWACF5E25K7TKFPRB4DGEV5MA-2025-04-14/&lt;/a>&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>技術書にしては珍しく、&lt;a class="link" href="https://www.chuko.co.jp/bunko/2019/06/206751.html" target="_blank" rel="noopener"
>中公新書から出ている。&lt;/a>&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>イーロン・マスクの米政府効率化省による取り組みとその&lt;a class="link" href="https://www.bbc.com/japanese/articles/c3wdznlnl2wo" target="_blank" rel="noopener"
>結果&lt;/a>を見れば明らかだろう。&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:4">
&lt;p>&lt;a class="link" href="https://www.maff.go.jp/j/tokei/sihyo/data/08.html" target="_blank" rel="noopener"
>農林水産省 農業労働力に関する統計&lt;/a>&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:5">
&lt;p>&lt;a class="link" href="https://www.maff.go.jp/j/tokei/sihyo/data/07.html" target="_blank" rel="noopener"
>農林水産省 経営体に関する統計&lt;/a>&amp;#160;&lt;a href="#fnref:5" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:6">
&lt;p>&lt;a class="link" href="https://agriport.jp/information/ap-2475/" target="_blank" rel="noopener"
>土壌分析と有機物で肥料コストを抑えよう！適正施肥のススメ&lt;/a>&amp;#160;&lt;a href="#fnref:6" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:7">
&lt;p>&lt;a class="link" href="https://www.nli-research.co.jp/report/detail/id=82236?site=nli" target="_blank" rel="noopener"
>ニッセイ基礎研究所　令和の米騒動が起きた背景と農業の現状－米の価格高騰はなぜ起きた?&lt;/a>&amp;#160;&lt;a href="#fnref:7" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:8">
&lt;p>seminarium&amp;#160;&lt;a href="#fnref:8" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:9">
&lt;p>今回は種子ではなく苗を使用するためだ。(ationes seminales)&amp;#160;&lt;a href="#fnref:9" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:10">
&lt;p>君たちのことだ。&amp;#160;&lt;a href="#fnref:10" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:11">
&lt;p>&lt;a class="link" href="https://www.mri.co.jp/knowledge/column/20250609.html" target="_blank" rel="noopener"
>三菱総合研究所 ヒューマノイドロボットへの期待：社会実装される5つの意義&lt;/a>&amp;#160;&lt;a href="#fnref:11" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:12">
&lt;p>&lt;a class="link" href="https://www.youtube.com/watch?v=jRLDPsoag6k" target="_blank" rel="noopener"
>ここ&lt;/a>に大変わかりやすい動画がある。&amp;#160;&lt;a href="#fnref:12" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:13">
&lt;p>数年前から様々な工程が自動化されて現場に導入されている
&lt;a class="link" href="https://www.kajima.co.jp/news/press/202310/13c1-j.htm" target="_blank" rel="noopener"
>成瀬ダムで自動化施工システムによる「現場の工場化」を実現&lt;/a>
&lt;a class="link" href="https://www.shimz.co.jp/solution/tech361/index.html" target="_blank" rel="noopener"
>ダムコンクリート自動打設システム&lt;/a>&amp;#160;&lt;a href="#fnref:13" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:14">
&lt;p>コンバインなら外周3ぶんは手動運転になる。一部に手動運転が必要であることはカタログの隅っこの小さい文字とか&lt;a class="link" href="https://www.maff.go.jp/j/nousin/noukan/tyotei/kizyun/attach/attach/pdf/tebiki-71.pdf" target="_blank" rel="noopener"
>規制省庁のガイド&lt;/a>とかに書いてある。最新機種は若干マシになったらしい。&amp;#160;&lt;a href="#fnref:14" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:15">
&lt;p>&lt;a class="link" href="https://www.mri.co.jp/knowledge/opinion/2025/202503_3.html" target="_blank" rel="noopener"
>三菱総合研究所 日本のスマート農業はなぜ普及が進まないのか？&lt;/a>&amp;#160;&lt;a href="#fnref:15" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:16">
&lt;p>&lt;a class="link" href="https://www.youtube.com/watch?v=pZetzJfzfU0" target="_blank" rel="noopener"
>このような動画が有限可算個存在する。&lt;/a> 無限と言うとグーで殴られる本当にひどい環境にいます。&amp;#160;&lt;a href="#fnref:16" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:17">
&lt;p>私は神農信仰が好きだ。&amp;#160;&lt;a href="#fnref:17" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:18">
&lt;p>農研機構が日本土壌インベントリーという本当に素晴らしいサービスを&lt;a class="link" href="https://soil-inventory.rad.naro.go.jp/" target="_blank" rel="noopener"
>リリース&lt;/a>している。&amp;#160;&lt;a href="#fnref:18" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:19">
&lt;p>2021年時点の分析で &lt;a class="link" href="https://www.jri.co.jp/MediaLibrary/file/report/researchreport/pdf/12484.pdf" target="_blank" rel="noopener"
>これ&lt;/a> であり、&lt;a class="link" href="https://www.chugoku-np.co.jp/articles/-/475814" target="_blank" rel="noopener"
>例えば中国地方の自治体はすべて確保に困難を抱えている。&lt;/a> 国家公務員ですら採用予定人数を&lt;a class="link" href="https://www.nikkei.com/article/DGXZQOUC286JS0Y4A820C2000000/" target="_blank" rel="noopener"
>確保できていない。&lt;/a>&amp;#160;&lt;a href="#fnref:19" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:20">
&lt;p>&lt;a class="link" href="https://www.ricoh.co.jp/magazines/workstyle/column/civil-engineering-shorthanded/" target="_blank" rel="noopener"
>リコー 土木業界の人手不足を解決する方法と成功事例｜生産性向上のカギとなるポイントも紹介&lt;/a>
しかし、&amp;ldquo;アニキ&amp;quot;について現場に行くだけで年収600万いった時代のそれを維持できる訳がないだろう。&amp;#160;&lt;a href="#fnref:20" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:21">
&lt;p>&lt;a class="link" href="https://www.mizuho-rt.co.jp/publication/report/2024/construction2410_01.html" target="_blank" rel="noopener"
>みずほリサーチ&amp;amp;テクノロジーズ 　建設分野における物価等動向について&lt;/a>　今は更に高騰している。&amp;#160;&lt;a href="#fnref:21" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:22">
&lt;p>&lt;a class="link" href="https://x.com/search?q=%E8%83%BD%E7%99%BB%E5%8D%8A%E5%B3%B6%E5%9C%B0%E9%9C%87%E3%80%80%E3%82%B9%E3%83%9E%E3%83%BC%E3%83%88%E3%82%B7%E3%83%86%E3%82%A3&amp;amp;src=typed_query&amp;amp;f=top" target="_blank" rel="noopener"
>これ&lt;/a>を見てほしい。国民の皆様の素晴らしい意見が拝聴できる。&amp;#160;&lt;a href="#fnref:22" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:23">
&lt;p>GITYはGSレジデンスの二階に位置しているが、エレベーターは止まらない。&amp;#160;&lt;a href="#fnref:23" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:24">
&lt;p>本当は「毎日豆乳も飲んでいる」としたかったが、最近GITYに宅配牛乳が導入されたため改稿された。話は変わるが牛乳（やコーラ）を飲むのか、それとも植物由来の代替ミルクを飲むのかによって深刻な対立を起こしている国もあるらしい。その国の首脳は白い家に住んでいることで知られている。&amp;#160;&lt;a href="#fnref:24" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>駄菓子屋ひびのば&amp;次世代の塾Sociusで働く私のおしごと</title><link>https://blog.gity.co.jp/posts/20250603/idema-intro/</link><pubDate>Tue, 03 Jun 2025 13:00:36 +0900</pubDate><guid>https://blog.gity.co.jp/posts/20250603/idema-intro/</guid><description>&lt;img src="https://blog.gity.co.jp/posts/20250603/idema-intro/me.jpg" alt="Featured image of post 駄菓子屋ひびのば&amp;次世代の塾Sociusで働く私のおしごと" />&lt;h2 id="初めまして">初めまして
&lt;/h2>&lt;p>今年2月から株式会社CATENASで働いています。いでまです。よろしくお願いします！
GITYで過ごす毎日が楽しくて仕方ないです＾＾&lt;/p>
&lt;h3 id="簡単に自己紹介">簡単に自己紹介
&lt;/h3>&lt;p>&lt;img src="https://blog.gity.co.jp/posts/20250603/idema-intro/me.jpg"
width="960"
height="1706"
srcset="https://blog.gity.co.jp/posts/20250603/idema-intro/me_hu11891927187628892022.jpg 480w, https://blog.gity.co.jp/posts/20250603/idema-intro/me_hu14704024710147426627.jpg 1024w"
loading="lazy"
alt="GITYのひびのばコーナー"
class="gallery-image"
data-flex-grow="56"
data-flex-basis="135px"
>&lt;/p>
&lt;ul>
&lt;li>名前：いでま&lt;/li>
&lt;li>年齢：24歳&lt;/li>
&lt;li>趣味：イベント企画&lt;/li>
&lt;li>特技：手話／打楽器／音速飯店（ボードゲーム）&lt;/li>
&lt;li>座右の銘：死ぬこと以外かすり傷&lt;/li>
&lt;li>マイブーム：働き方を模索しながら働くこと&lt;/li>
&lt;/ul>
&lt;h3 id="なんの仕事してるの">なんの仕事してるの？
&lt;/h3>&lt;p>GITYでの教育事業「Socius（ソキウス）」の運営、駄菓子屋「ひびのば」の運営・インフルエンサーをしています。
誰もが主体的に学び続けることができる社会をつくるために、さまざまな角度から活動を広げていくこの仕事が楽しいです！&lt;/p>
&lt;h3 id="sociusのミッション">Sociusのミッション
&lt;/h3>&lt;p>&lt;img src="https://blog.gity.co.jp/posts/20250603/idema-intro/socius.jpg"
width="3024"
height="4032"
srcset="https://blog.gity.co.jp/posts/20250603/idema-intro/socius_hu2670436249309452796.jpg 480w, https://blog.gity.co.jp/posts/20250603/idema-intro/socius_hu14378082573409474997.jpg 1024w"
loading="lazy"
alt="駄菓子のパズルを作りました!"
class="gallery-image"
data-flex-grow="75"
data-flex-basis="180px"
>&lt;/p>
&lt;p>Sociusはいわゆる学習塾とフリースクールを運営しています。
「いわゆる」と付けたのは、この「塾」「フリースクール」というラベリングがイメージを操作してしまっているんじゃないかと考えたからです。&lt;/p>
&lt;p>Sociusのミッションは&amp;quot;出会い、繋がり、誰もが”共育”の主人公。“&lt;/p>
&lt;p>学校に「行かない」という選択が、ネガティブな不登校のイメージではなく、
シンプルな、新たな選択肢として捉えることが当たり前になるような社会を作りたいと思っています。&lt;/p>
&lt;p>学習塾も同じで、従来の知識詰め込み型の塾ではなく、勉強に向かうモチベーションを高めることを目的とした、生徒と大学生講師間での”学び合い”を重視しています。&lt;/p>
&lt;h3 id="駄菓子屋ひびのばってなに">駄菓子屋ひびのばってなに？
&lt;/h3>&lt;p>大学生と一緒に運営している駄菓子屋さんです！今年の4月25日にオープンしました！&lt;/p>
&lt;ul>
&lt;li>営業日：毎週火曜日・金曜日&lt;/li>
&lt;li>時間：15:00-18:00&lt;/li>
&lt;li>場所：&lt;a class="link" href="https://g.co/kgs/FPmur5c" target="_blank" rel="noopener"
>群馬県前橋市南町３丁目74−１１&lt;/a>
まだ営業日が少ないのですが、徐々に増やしていけたらと思っています！
また、店舗数も増やして、いろんな地域の方へ駄菓子屋で生まれるコミュニティを楽しんでもらえるようにしたいなと思っています！&lt;/li>
&lt;/ul>
&lt;h4 id="snsも頑張ってます">SNSも頑張ってます
&lt;/h4>&lt;p>ひびのばは&lt;a class="link" href="https://www.instagram.com/hibinoba_dagashi/reels/" target="_blank" rel="noopener"
>Instagram&lt;/a>で発信をしています！
このアカウントも、県内の大学生たちと一緒に作っています！SNSマーケティングを学生同士で学び合える場として、日々奮闘中です！
一見、SNSの世界はキラキラしているように見えますが、緻密に分析と改善を重ねている学生たちの姿は本当にたくましく、リスペクトが止まりません！
SNS班の子達が作ってくれた台本の言葉ひとつひとつの意味や意図を読み解きながら、一生懸命頑張っているのでぜひチェックしてみてください！お店にも遊びに来てくださいね〜！&lt;/p>
&lt;h3 id="仕事の中で大事にしていること">仕事の中で大事にしていること
&lt;/h3>&lt;h4 id="自己決定の機会をなるべく多く作る">自己決定の機会をなるべく多く作る
&lt;/h4>&lt;p>学校に通わないという選択をとった子たちは、社会の中で学んでいくということであり、一つ一つの意思決定がその後の人生に大きな影響を与えることがあります。
日々の小さな決断も、学校に行く・行かないという大きな決断も、子どもが「自分で決めたのだから頑張ろう」と思えるような環境づくりを重視していきたいと思っています。&lt;/p>
&lt;p>駄菓子屋の運営でも、Sociusの学生と関わるときでも、大事にしていることは共通しています。学生の主体性を尊重し、やりたいこと・学びたい学習が実現できる場所にしてほしいという思いのもと、活動しています！&lt;/p>
&lt;p>どこまで自分の意見を伝え、どこからどうやって学生に任せるのか。&lt;/p>
&lt;p>真のリーダーシップとか、コミュ力とか、いろんなテーマで対話を繰り返し、学びでお腹いっぱいになるような、そんな毎日です…！&lt;/p>
&lt;h2 id="終わりに">終わりに
&lt;/h2>&lt;p>GITYを運営する株式会社CATENASでの生活について、考えていることなどざっくばらんに書かせていただきました。いかがでしたか〜！&lt;/p>
&lt;p>GITYは今日も、平和です。どれくらい平和かというと、学生が甘食を分け合いっこしてくれたり、その横で急須でお茶を入れてくれたり、それくらい平和です。あと社会人の方がかわいい駄菓子をちょこちょこ買って交流してくれるのも、嬉しいです、萌えます！＾＾&lt;/p>
&lt;p>GITYに来てから約４ヶ月。穏やかさと新しさ、面白さを兼ね揃えたすげえ居場所だなと思います！
これからも、楽しみながら学びを積み重ねて成長していけるよう頑張ります！&lt;/p>
&lt;p>最後まで読んでいただきありがとうございました！&lt;/p>
&lt;!-- markdownlint-disable no-alt-text -->
&lt;p>&lt;img src="https://blog.gity.co.jp/posts/20250603/idema-intro/gity.jpg"
width="1365"
height="2048"
srcset="https://blog.gity.co.jp/posts/20250603/idema-intro/gity_hu12121812624083330478.jpg 480w, https://blog.gity.co.jp/posts/20250603/idema-intro/gity_hu17929420803654503529.jpg 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="66"
data-flex-basis="159px"
>&lt;/p></description></item><item><title>お前のバックエンドサーバーは20行でMCP Serverになる</title><link>https://blog.gity.co.jp/posts/20250503/gin-mcp-server/</link><pubDate>Sat, 03 May 2025 02:26:19 +0900</pubDate><guid>https://blog.gity.co.jp/posts/20250503/gin-mcp-server/</guid><description>&lt;img src="https://blog.gity.co.jp/posts/20250503/gin-mcp-server/ai.png" alt="Featured image of post お前のバックエンドサーバーは20行でMCP Serverになる" />&lt;p>世間の技術の話題といえばLLMでもちきりになってしまいました。QiitaやZennのトレンドはMCP ServerやLLMの話題で溢れかえっています。&lt;/p>
&lt;p>私はそんなAIに溢れかえっている今の風潮があまり好きではないのですが、全身逆張りオタクのような&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>言動ばかりしていては世間に取り残されるのみです。&lt;/p>
&lt;p>そんなわけで私もこの流行に便乗し、LLMくんのコミュニケーションツールであるMCP Serverを実装していきます。&lt;/p>
&lt;h2 id="事前知識のおさらい">事前知識のおさらい
&lt;/h2>&lt;h3 id="mcpとは-llmのtypecと呼ばれる謎の物">MCPとは? LLMのTypeCと呼ばれる謎の物
&lt;/h3>&lt;p>まず、「MCPとはなんぞや？」という疑問に答えましょう。&lt;/p>
&lt;p>MCP（Model Context Protocol）は、LLMと外部のサービス/アプリケーション間で安定的かつ効率的に通信するために設計された通信プロトコルです。アプリケーション層のプロトコルであり、平たく言えば特定のJSONを返すREST APIサーバーです。&lt;/p>
&lt;p>簡単に言えば「LLMと喋るためのUSB Type-Cケーブル」のような役割を果たします。&lt;/p>
&lt;p>従来、LLMと外部サービスを繋げようとすると、OpenAI APIのような独自仕様のREST APIやWebSocket、果てはRPCのラッパーなど、実装者ごとにバラバラな通信方法が使われてきました。&lt;/p>
&lt;p>MCPはこれを標準化し、「モデルとクライアント及び情報源の間でやり取りするメッセージの形式・流れ・エラー処理」を統一することで、LLMが外部サービスへアクセスしやすくなり、ハルシネーションを減らしたり作業を代行したりできます。&lt;/p>
&lt;h3 id="mcp-serverとは">MCP Serverとは
&lt;/h3>&lt;p>MCP Serverとは、このMCPプロトコルを話せるサーバー側の実装を指します。具体的には、&lt;/p>
&lt;ul>
&lt;li>LLMから要求された情報を提供する&lt;/li>
&lt;li>LLMに従って副作用を伴う特定の処理を行う&lt;/li>
&lt;/ul>
&lt;p>といった機能を備えたサーバーのことです。&lt;/p>
&lt;p>MCPが実装された任意のアプリケーションと任意のモデルが通信できることにより、サービスを自由に接続できるようになります。IFTTTのLLM版というのがわかりやすい表現でしょうか。&lt;/p>
&lt;p>とはいえ、MCPの仕様はそこそこ複雑です。&lt;/p>
&lt;p>「じゃあ俺が今からMCP Serverの全プロトコル実装を書くぞ！」というのは、なかなか骨が折れます。&lt;/p>
&lt;h2 id="ckanthonygin-mcpはすごいぞ">ckanthony/gin-mcpはすごいぞ
&lt;/h2>&lt;p>MCP Serverが何をするものかというのがわかったところで早速作っていくわけですが、一からこのプロトコルを実装するのはちょっと面倒です。&lt;/p>
&lt;p>以下のようなGolang用のライブラリが公開されてはいますが、これらを利用して構築しただけでは世間にあふれかえる記事と全く同じつまらないものになってしまいます。&lt;/p>
&lt;p>私のような怠惰な人間はLLMによる効率化のための手間すら面倒なのです。&lt;/p>
&lt;p>そんな私にうってつけのライブラリがこちら。&lt;a class="link" href="https://github.com/ckanthony/gin-mcp" target="_blank" rel="noopener"
>ckanthony/gin-mcp&lt;/a>です。&lt;/p>
&lt;p>このライブラリは名前の通り、みんな大好きGinフレームワークと組み合わせて「超お手軽にMCP Serverを立てられる」ことを目的に作られています。&lt;/p>
&lt;p>MCPの中には情報を取得・操作するインターフェースを提供するToolと呼ばれるものがあります。LLMが実際に使えるTool(道具)というわけです。&lt;code>gin-mcp&lt;/code>はGinで構築されたToolを一瞬で作成できます。&lt;/p>
&lt;h2 id="gityで開発されている実際のプロジェクトに導入してみた">GITYで開発されている実際のプロジェクトに導入してみた
&lt;/h2>&lt;h3 id="元になるコード">元になるコード
&lt;/h3>&lt;p>以前にこのブログで、&lt;a class="link" href="https://blog.gity.co.jp/posts/20250116/seedsn-tech/" >Seedsnの技術スタックを紹介&lt;/a>しました。今回はSeedsnにGinを導入していきます。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="nx">config&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">conf&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Get&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1">// 設定を取得
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">if&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="kc">nil&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nx">err&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Initialize the Gin engine.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">slog&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Initializing the Gin engine&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">engine&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">gin&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Default&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">setRoute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="nx">engine&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// 別の関数でルーティングを設定
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Run the server.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">slog&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Starting the server&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">engine&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Run&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">config&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ServerPort&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="kc">nil&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nx">err&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>SeedsnのAPIサーバーの起動処理を行っている部分です。直接的な関与のない一部の処理を省略しています。&lt;/p>
&lt;p>今回はこれに手を加えていきます。&lt;/p>
&lt;h3 id="追加するコード">追加するコード
&lt;/h3>&lt;p>適当な場所で以下のような関数を定義しましょう。やることはこれだけです。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;github.com/catenas-g/seedsn/conf&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">mcpserver&lt;/span> &lt;span class="s">&amp;#34;github.com/ckanthony/gin-mcp&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;github.com/gin-gonic/gin&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">func&lt;/span> &lt;span class="nf">setMCP&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">e&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="nx">gin&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Engine&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">s&lt;/span>&lt;span class="o">:=&lt;/span> &lt;span class="nx">mcpserver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">New&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">e&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="nx">mcpserver&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Config&lt;/span>&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">Name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s">&amp;#34;Seedsn MCP Server&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">Description&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s">&amp;#34;Seedsn MCP Server&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">BaseURL&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s">&amp;#34;https://localhost:8080/&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">s&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Mount&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;/mcp&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>設定の値はそれぞれ書き換えてください。&lt;code>ckanthony/gin-mcp&lt;/code>は&lt;code>gin.Engine&lt;/code>に対していろいろ加工をしてあげることでMCP Server化します。&lt;/p>
&lt;p>関数を作成したら、これを実際に呼び出します。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="nx">config&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">conf&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Get&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="c1">// 設定を取得
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">if&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="kc">nil&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nx">err&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="c1">// Initialize the Gin engine.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">slog&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Initializing the Gin engine&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="nx">engine&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">gin&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Default&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="nf">setRoute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="nx">engine&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// 別の関数でルーティングを設定
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line hl">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="nf">setMCP&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">engine&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// Call to set up the MCP server
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">&lt;span class="c1">// Run the server.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">slog&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Starting the server&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">engine&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Run&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">config&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ServerPort&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="kc">nil&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nx">err&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>ルーティングの設定直後に&lt;code>setMCP&lt;/code>を呼んであげるだけです。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-txt" data-lang="txt">&lt;span class="line">&lt;span class="cl">INFO[0000] Starting conversion of 2 routes to MCP tools...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">INFO[0000] Processing route: GET /api/v1/projects -&amp;gt; OpID: GET_api_v1_projects
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">INFO[0000] Processing route: GET /api/v1/projects/:id -&amp;gt; OpID: GET_api_v1_projects_id
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">INFO[0000] Finished route conversion. Generated 2 tools.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">INFO[0000] [SSE] Creating new transport at /mcp
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">INFO[0000] [Transport DEBUG] Registered handler for method: initialize
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">INFO[0000] [Transport DEBUG] Registered handler for method: tools/list
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">INFO[0000] [Transport DEBUG] Registered handler for method: tools/call
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">INFO[0000] [Server Mount DEBUG] Defining GET /mcp route
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">[GIN-debug] GET /mcp --&amp;gt; github.com/ckanthony/gin-mcp.(*GinMCP).handleMCPConnection-fm (7 handlers)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">INFO[0000] [Server Mount DEBUG] Defining POST /mcp route
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">[GIN-debug] POST /mcp --&amp;gt; github.com/ckanthony/gin-mcp.(*GinMCP).Mount.func2 (7 handlers)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">03:36:46.997 INFO Starting the server
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">[GIN-debug] Listening and serving HTTP on :8080
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">hayao@Hayao-XPS9350 ~/G/s/api (Hayao0819/mcp-server) [1]&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>サーバー起動時に見慣れないログが出力されれば。MCPサーバの構築は完了です。&lt;/p>
&lt;h2 id="clineから呼び出してみた">Clineから呼び出してみた
&lt;/h2>&lt;h3 id="clineにmcp-serverを登録する">ClineにMCP Serverを登録する
&lt;/h3>&lt;p>テストとしてClineから呼び出してみましょう。今回は呼び出しのモデルに&lt;code>gemini-2.0-flash-001&lt;/code>を利用しています。&lt;/p>
&lt;p>以下のようにMCP Server登録します。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;mcpServers&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;Seedsn&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;url&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;http://localhost:8080/mcp&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;disabled&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;autoApprove&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;img src="https://blog.gity.co.jp/posts/20250503/gin-mcp-server/cline-settings.png"
width="329"
height="506"
srcset="https://blog.gity.co.jp/posts/20250503/gin-mcp-server/cline-settings_hu3344499603988198829.png 480w, https://blog.gity.co.jp/posts/20250503/gin-mcp-server/cline-settings_hu3822579754924851180.png 1024w"
loading="lazy"
alt="Clineの設定画面"
class="gallery-image"
data-flex-grow="65"
data-flex-basis="156px"
>&lt;/p>
&lt;h3 id="実際に呼び出してみる">実際に呼び出してみる
&lt;/h3>&lt;p>次のようなプロンプトでSeedsnのAPIを使うように指示します。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-txt" data-lang="txt">&lt;span class="line">&lt;span class="cl">私は群馬に住んでいるパソコンが好きなオタクです。Seedsnに登録されているプロジェクトのうち、私におすすめのものを教えてください。
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;img src="https://blog.gity.co.jp/posts/20250503/gin-mcp-server/cline-chat-1.png"
width="1338"
height="486"
srcset="https://blog.gity.co.jp/posts/20250503/gin-mcp-server/cline-chat-1_hu5590512463706292896.png 480w, https://blog.gity.co.jp/posts/20250503/gin-mcp-server/cline-chat-1_hu8213054284249915795.png 1024w"
loading="lazy"
alt="ClineでGeminiと会話"
class="gallery-image"
data-flex-grow="275"
data-flex-basis="660px"
>&lt;/p>
&lt;p>どうやらちゃんとMCP Serverを使ってくれそうです。&lt;/p>
&lt;p>APIの返答が色々と表示された後……&lt;/p>
&lt;p>&lt;img src="https://blog.gity.co.jp/posts/20250503/gin-mcp-server/cline-chat-2.png"
width="1119"
height="592"
srcset="https://blog.gity.co.jp/posts/20250503/gin-mcp-server/cline-chat-2_hu10454321508790462155.png 480w, https://blog.gity.co.jp/posts/20250503/gin-mcp-server/cline-chat-2_hu16431175075151540381.png 1024w"
loading="lazy"
alt="ClineがMCPを使ってお返事してくれた！"
class="gallery-image"
data-flex-grow="189"
data-flex-basis="453px"
>&lt;/p>
&lt;p>無事にちゃんと情報を取得して返してくれました。&lt;/p>
&lt;h2 id="終わり">終わり
&lt;/h2>&lt;p>僅か20行程度でMCP Serverと進化させることができました。エンドポイントやハンドラは一切触れず、&lt;code>gin.Engine&lt;/code>に細工をしただけです。&lt;/p>
&lt;p>残念ながら認証についての実装を行っていないのでプロジェクトの追加や削除といったことは行えませんが、それでもこの手軽さには驚きです。&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>&lt;/p>
&lt;p>もう少ししっかりと設定をしたうえで、Seedsnのプロジェクトを誰でもLLMで活用できるようにMCP Serverの実装を進めていけたらと思います。&lt;/p>
&lt;p>皆さんもGinを使ったプロジェクトがあったらぜひ導入してみてください。それでは、また今度。&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>比喩表現であり私自身はｹｯｼﾃ&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>驚き屋さんになったのは初めてなのですが、うまくできていますか？&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>東方Projectの音楽をSC-88ST Proで聴ける環境を構築した話</title><link>https://blog.gity.co.jp/posts/20250323/touhou-midi/</link><pubDate>Sun, 23 Mar 2025 20:51:12 +0900</pubDate><guid>https://blog.gity.co.jp/posts/20250323/touhou-midi/</guid><description>&lt;img src="https://blog.gity.co.jp/posts/20250323/touhou-midi/playing-th06.png" alt="Featured image of post 東方Projectの音楽をSC-88ST Proで聴ける環境を構築した話" />&lt;p>こんにちは、山田ハヤオです。&lt;/p>
&lt;p>皆さんは東方projectというものをご存知でしょうか？&lt;/p>
&lt;p>1996年から続く弾幕シューティングゲームのシリーズのことなのですが、私はそのゲームの音楽が大好きです。&lt;/p>
&lt;p>ということで今回は、GITYでこのゲームの音楽を聞いていきます。&lt;/p>
&lt;h2 id="midiとは">MIDIとは
&lt;/h2>&lt;p>音楽をやっている方はご存知だと思いますが、昔から存在する音楽形式にMIDIというものがあります。&lt;/p>
&lt;p>mp3やwav等の音楽形式は「音声データそのもの」を持っていますが、MIDIは「演奏する方法」を持っているデータ形式です。&lt;/p>
&lt;p>MIDIは「どこの鍵盤を何秒押すのか」という情報しか持っていないため、それを鳴らすための音源が必要になります。&lt;/p>
&lt;h2 id="sc-88stpro">SC-88STPro
&lt;/h2>&lt;p>現代ではMIDIの音源にはソフトウェアを使うことが大半ですが、かつては&lt;strong>ハードウェアMIDI音源&lt;/strong>という、MIDIを鳴らすための専用の器械がありました。&lt;/p>
&lt;p>東方Projectの初期の頃のゲームもこのハードウェア音源が無いと当時の音を再生することができません。&lt;/p>
&lt;p>ということでヤフオクで入手したのがこちらですドン！&lt;/p>
&lt;p>&lt;img src="https://blog.gity.co.jp/posts/20250323/touhou-midi/sc-88st-pro.png"
width="2048"
height="1043"
srcset="https://blog.gity.co.jp/posts/20250323/touhou-midi/sc-88st-pro_hu10530843575717860857.png 480w, https://blog.gity.co.jp/posts/20250323/touhou-midi/sc-88st-pro_hu17037865050581883109.png 1024w"
loading="lazy"
alt="SC-88ST Pro"
class="gallery-image"
data-flex-grow="196"
data-flex-basis="471px"
>&lt;/p>
&lt;p>入手してしまいました。&lt;strong>SC-88ST Pro&lt;/strong>です。&lt;/p>
&lt;p>東方Project作品の推奨音源はSC-88Proです。SC-88ST ProはSC-88Proと音源として完全な互換性があります。違いは液晶の有無で、所謂廉価版というやつです。&lt;/p>
&lt;p>このSC-88ST Proを鳴らしていこうと思います。&lt;/p>
&lt;h2 id="音を鳴らす">音を鳴らす
&lt;/h2>&lt;p>今回は16音色の構成です。いつか32音構成もやってみたいところですが、MIDIインターフェースを1つしか持っておらず、2系統のものは高価なので暫く先の話になりそうです。&lt;/p>
&lt;h3 id="構成">構成
&lt;/h3>&lt;ul>
&lt;li>SC-88ST Pro&lt;/li>
&lt;li>LEKATO USB MIDI Interface
Amazonで2,000円でした&lt;/li>
&lt;li>Windowsが動作しているPC
WindowsVista以前が用意できると安定します&lt;/li>
&lt;li>3.5mmジャックを備えた有線イヤホン&lt;/li>
&lt;/ul>
&lt;p>PCとMIDI InterfaceをUSBで接続します。ドライバは自動でインストールされました。&lt;/p>
&lt;p>MIDI InterfaceのMIDI OutとSC-88ST ProのMIDI Inを接続します。&lt;/p>
&lt;p>最後にSc-88ST Proのフロントの3.5mmイヤホンジャックにイヤホンを挿せば配線は完了です。&lt;/p>
&lt;h3 id="必要なソフトウェア">必要なソフトウェア
&lt;/h3>&lt;ul>
&lt;li>音を鳴らすゲーム・MIDI再生ソフトウェア
今回は東方紅魔郷を再生します&lt;/li>
&lt;li>CoolSoft MIDIMapper&lt;/li>
&lt;/ul>
&lt;h3 id="midi-mapperについて">MIDI Mapperについて
&lt;/h3>&lt;p>Windows XPまでのWindows OSには規定のMIDIデバイスを設定するMIDI Mapperという機能がありました。&lt;/p>
&lt;p>しかしこの機能はWindows Vistaで廃止されています。
この問題は東方ProjectのようなMIDIの再生デバイスを指定できないゲームにおいて致命的です。&lt;/p>
&lt;p>そこで利用するのが&lt;code>CoolSoft MIDIMapper&lt;/code>です。仮想的なMIDIデバイスを作成・リダイレクトすることで任意のMIDIデバイスを規定の出力先に変更できるツールです。&lt;/p>
&lt;p>以下の公式サイトからダウンロード・インストールが可能です。&lt;/p>
&lt;p>&lt;a class="link" href="https://coolsoft.altervista.org/en/midimapper" target="_blank" rel="noopener"
>MIDIMapper | CoolSoft&lt;/a>&lt;/p>
&lt;h3 id="東方紅魔郷">東方紅魔郷
&lt;/h3>&lt;p>東方紅魔郷は前述した東方Projectの第6作品目の弾幕型シューティングゲームです。Windowsで動作する東方Project作品の中で最古の作品です。&lt;/p>
&lt;p>第1作から第5作は旧作と呼ばれ、現代のコンピュータ(PC/AT互換機)ではないPC-98シリーズでのみ動作します。&lt;/p>
&lt;p>98シリーズの実機は現在入手困難なため、動作させるにはエミュレータを利用するのが主流ですが今回は割愛します。
(私の技量不足もあり、エミュレータから音を出せませんでした。)&lt;/p>
&lt;p>第6作以降はWindowsで動作しますが、MIDIでの出力に対応しているのは第6作～第8作目のみ&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>となります。それ以降の作品ではMIDIは非対応です。&lt;/p>
&lt;p>また、東方紅魔郷にはWindows 10以降のOSで利用すると暴走するバグがありますが以下のDLLを導入することで回避しています。&lt;/p>
&lt;p>&lt;a class="link" href="https://github.com/crosire/d3d8to9" target="_blank" rel="noopener"
>crosire/d3d8to9: A D3D8 pseudo-driver which converts API calls and bytecode shaders to equivalent D3D9 ones.&lt;/a>&lt;/p>
&lt;h3 id="実際の様子">実際の様子
&lt;/h3>&lt;p>&lt;img src="https://blog.gity.co.jp/posts/20250323/touhou-midi/playing-th06.png"
width="2048"
height="1536"
srcset="https://blog.gity.co.jp/posts/20250323/touhou-midi/playing-th06_hu14668384102713558024.png 480w, https://blog.gity.co.jp/posts/20250323/touhou-midi/playing-th06_hu9533262150505708414.png 1024w"
loading="lazy"
alt="東方紅魔郷をSC-88ST Proで再生する様子"
class="gallery-image"
data-flex-grow="133"
data-flex-basis="320px"
>&lt;/p>
&lt;p>第8作品目である東方永夜抄でも再生してみました。&lt;/p>
&lt;p>&lt;img src="https://blog.gity.co.jp/posts/20250323/touhou-midi/playing-th08.png"
width="2048"
height="1536"
srcset="https://blog.gity.co.jp/posts/20250323/touhou-midi/playing-th08_hu8188766307945103294.png 480w, https://blog.gity.co.jp/posts/20250323/touhou-midi/playing-th08_hu16392051718901342881.png 1024w"
loading="lazy"
alt="東方永夜抄をSC-88ST Proで再生する様子"
class="gallery-image"
data-flex-grow="133"
data-flex-basis="320px"
>&lt;/p>
&lt;h2 id="音を収録する">音を収録する
&lt;/h2>&lt;p>オーディオインターフェースを利用してSC-88ST Proからの音を収録します。&lt;/p>
&lt;p>今回はインターフェースとして&lt;strong>QX1002USB&lt;/strong>を利用します。&lt;/p>
&lt;h3 id="ケーブル配線">ケーブル配線
&lt;/h3>&lt;p>MIDI InterfaceとPCの接続に変化はありません。今まではイヤホンに出力していたものをインターフェースに流し込みます。&lt;/p>
&lt;p>SC-88ST Proの裏にあるRCA出力からInterfaceに出力し、その音をAudacityで拾います。&lt;/p>
&lt;p>このときのインターフェースやミキサの音量調整は、GITYにいる音楽系に詳しい先輩に行ってもらいました。&lt;/p>
&lt;p>&lt;img src="https://blog.gity.co.jp/posts/20250323/touhou-midi/audio-interface.png"
width="1536"
height="2048"
srcset="https://blog.gity.co.jp/posts/20250323/touhou-midi/audio-interface_hu1226696364589361438.png 480w, https://blog.gity.co.jp/posts/20250323/touhou-midi/audio-interface_hu17574558697453162180.png 1024w"
loading="lazy"
alt="収録をしている様子"
class="gallery-image"
data-flex-grow="75"
data-flex-basis="180px"
>&lt;/p>
&lt;p>収録にあたって、安定動作のためにゲームを動作させる(MIDIを出力させる)PCと、Audacityを動作させるPCを分けることにしました。&lt;/p>
&lt;p>奥にあるのはGITYでレガシーなソフトウェアを動作させるために私が持ち込んだWindows 7が動作しているノートPCです。&lt;/p>
&lt;p>手前のPCにオーディオインターフェースを接続し、デジタル化された音をAudacityで録音しています。&lt;/p>
&lt;h2 id="終わり">終わり
&lt;/h2>&lt;p>&lt;strong>ハードウェアMIDI音源を聴けるシェアオフィスはGITYだけ&lt;/strong>と言えるように環境を整えたいですね。 しかしそんなシェアオフィスの需要はあるのだろうか。&lt;/p>
&lt;p>次回は東方Project発足当時のPCであるPC-98シリーズを分解し復活させようと思います。(失敗したらボツにします。)&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>正確には第9作品「東方花映塚」の体験版まで。旧作については知らないです。&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>人工の海に執着する群馬県民の昏い情熱</title><link>https://blog.gity.co.jp/posts/20250319/iot-shrimp/</link><pubDate>Wed, 19 Mar 2025 18:18:00 +0900</pubDate><guid>https://blog.gity.co.jp/posts/20250319/iot-shrimp/</guid><description>&lt;img src="https://blog.gity.co.jp/posts/20250319/iot-shrimp/tank_naname.jpg" alt="Featured image of post 人工の海に執着する群馬県民の昏い情熱" />&lt;p>私は富山の出で、実家は漁港近くにある。海なし県に囚われた私を心配しているのか、祖母は私が帰省するたびに地場の魚を振る舞ってくれる。祖母が笑顔で「こちらの魚は美味しいだろう、新鮮さが違うから」と話してくれるたびに、私も魚のおいしさ以上に嬉しくなる。
ところで東京-地方漁港スシ議論という概念がある。日本で一番カネとヒトが集まる都市である東京に上等なネタも同じく一極集中するから地方の漁港近辺で食べるスシが新鮮で一番うまいというのは幻想であると主張する東京人と、普通に考えて釣りたてを食べるのが一番うまいだろと主張するその他&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>の県民の対立である。これら主張の真偽はさておき&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>、高速道路開通やコールドチェーンの発達によって群馬県の魚介事情は相当に改善された。もちろん群馬県の超巨大マーケットにアクセスするために物流システムが改善された訳ではなく、東京と日本海側を繋ぐためだ。話は変わるが、古来から抜荷の対策というものは難しいもので、港湾や鉄道ではコンテナの導入まで行方不明になる荷物が相当多かったらしい。
なにはともあれ日本海側の漁港で朝に採れた魚は翌日早朝のセリまでに東京に届き、その日のうちに飲食店や小売店に並ぶ。また、漁港近辺のスーパーマーケットでは11時ごろからその日の朝に取れた魚が並び始める。少し話が戻るが、私の祖母は公務員を定年まで勤め上げた厳格な人で、何事も早め早めに済ませてしまう。例えば、私が帰省する2~3日前には魚を買っておいてくれるらしい。&lt;/p>
&lt;hr>
&lt;p>本稿ではGITYで行われているクルマエビの海上養殖の環境監視システムの概要について示す。作成ガイド形式になっているのでエビを養殖したい方はどうぞ。このシステムは文字通り私一人の手によって&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup>一晩で作成されたためアラが多いかもしれない。ダシもよく出る。しかし、昨年9月から現在に至るまで24/365で特にトラブルなく運用できている。&lt;/p>
&lt;p>&lt;img src="https://blog.gity.co.jp/posts/20250319/iot-shrimp/tank_naname.jpg"
width="4096"
height="3072"
srcset="https://blog.gity.co.jp/posts/20250319/iot-shrimp/tank_naname_hu1794484525331101304.jpg 480w, https://blog.gity.co.jp/posts/20250319/iot-shrimp/tank_naname_hu14020931367558052745.jpg 1024w"
loading="lazy"
alt="エビ養殖槽の外観"
class="gallery-image"
data-flex-grow="133"
data-flex-basis="320px"
>&lt;/p>
&lt;p>&lt;img src="https://blog.gity.co.jp/posts/20250319/iot-shrimp/ebi.png"
width="4032"
height="3024"
srcset="https://blog.gity.co.jp/posts/20250319/iot-shrimp/ebi_hu9961153272276161291.png 480w, https://blog.gity.co.jp/posts/20250319/iot-shrimp/ebi_hu550171669645509727.png 1024w"
loading="lazy"
alt="いきいき動くエビ"
class="gallery-image"
data-flex-grow="133"
data-flex-basis="320px"
>&lt;/p>
&lt;h2 id="はじめに">はじめに
&lt;/h2>&lt;p>まず、GITYのエビ養殖水槽に設置された監視システムはあくまでデモンストレーション用であり、構想/設計のごく一部であることを断っておく。このシステムは&lt;strong>無駄に&lt;/strong>どこかの財閥系企業の鉱山監視システムや&lt;strong>無駄に&lt;/strong>農研機構の通い農業支援システムを参考にして構築され、&lt;strong>無駄に&lt;/strong>農業情報学会のUECSをjsonに改変したものを通信プロトコルとして使用している。これによって&lt;strong>無駄に&lt;/strong>拡張性が高く、なにかの間違いでエビ水槽がGITYフロアを埋め尽くしたり群馬県庁の全フロアがいきなり植物工場と化しても問題なく対応可能である。信頼性が重要なら冗長構成の構築や産業用グレードのボードへの入れ替えも容易に可能である。更に、&lt;strong>無駄に&lt;/strong>WifiやBLE,LoRaといった通信規格にも対応でき、室内の数メートルから屋外の数キロメートル単位でのセンシングも可能である。記録頻度とバーターにはなるが、年単位でセンサ端末の電池を保たせることもできる。完全にオフグリッドでシステム全体を動作させることも、データ基盤をクラウドに設置することも可能だ。
GITYの養殖水槽に置かれているのは最小構成を少しだけ拡張した、有線ベースのコンパクトなバージョンである。次に現物の写真を示す。（設計ミスあり。分かった方は直接対面で私まで！先着で素敵なプレゼント。）&lt;/p>
&lt;p>&lt;img src="https://blog.gity.co.jp/posts/20250319/iot-shrimp/arduino.jpg"
width="4096"
height="3072"
srcset="https://blog.gity.co.jp/posts/20250319/iot-shrimp/arduino_hu7884080503107229097.jpg 480w, https://blog.gity.co.jp/posts/20250319/iot-shrimp/arduino_hu8871938134149164329.jpg 1024w"
loading="lazy"
alt="ブレッドボードに刺されたセンサとマイコンの写真"
class="gallery-image"
data-flex-grow="133"
data-flex-basis="320px"
>&lt;/p>
&lt;p>&lt;em>&lt;strong>ふざけているのか？&lt;/strong>&lt;/em>&lt;/p>
&lt;p>しかし現実のプロトタイピングなんてこんなものである。総務省のICTスタートアップリーグも書類通過した。ここで陰謀論者に朗報――政府は我々を監視していない。&lt;/p>
&lt;h2 id="構成概観">構成概観
&lt;/h2>&lt;p>ラズパイにマイコンを繋いだだけ。私の名前を横断検索ツールに入れる&lt;sup id="fnref:4">&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref">4&lt;/a>&lt;/sup>のは少し話を聞いてからでも遅くは無いと思う。思い出してもらいたいが、日本の誇る産業機械もモーターをたくさん繋いだだけだし、ここ何年間もS&amp;amp;P500の好成績を支えてきたビッグテックの筆頭、Googleの製品も群馬県の高卒（私のことだ）をストーキングして広告をクリックさせるだけのものだ。&lt;/p>
&lt;p>このシステムは大きく分けて2つ、大規模化する場合には3つの部分に分かれる。センサを制御するマイコン部分、マイコンから送られるデータを受信し蓄積する小型Linuxマシン、そして小型PCに蓄積されたデータを纏めるクラウドサーバないしメインマシンである。今回のシステムではマイコンを一つと小型Linuxマシンを一つのシンプルな構成になった。更に小さくしたい場合にはGPIOのあるRaspberry Piのようなマシンに直接センサを繋いでやればよい。
概要としては以下の図のようになる。&lt;/p>
&lt;p>&lt;img src="https://blog.gity.co.jp/posts/20250319/iot-shrimp/ppt.png"
width="1726"
height="973"
srcset="https://blog.gity.co.jp/posts/20250319/iot-shrimp/ppt_hu11718141890478178934.png 480w, https://blog.gity.co.jp/posts/20250319/iot-shrimp/ppt_hu5491087949574870170.png 1024w"
loading="lazy"
alt="ありえないくらい適当なパワポ"
class="gallery-image"
data-flex-grow="177"
data-flex-basis="425px"
>&lt;/p>
&lt;h3 id="センサー選定">センサー選定
&lt;/h3>&lt;p>なんでもよい。強いて言うなら、湿度センサを流通過程で湿度管理しているサプライヤは秋月だけしか確認できていないという情報があった。適当に測りたいものが測れるものを買う。今回はBME280、MH-Z19C、DS18B20などを使用する。DS18B20は使用しやすく加工されたものが、なぜか生のセンサと変わらない値段で販売されているため注意。BME系列のセンサは海外通販でお安いものも見つかる。好みで使い分ける。センサー選定の最も重要なポイントは値段や精度よりも使いやすいライブラリがあるかどうかだ。一番のコストは人件費！&lt;/p>
&lt;h3 id="マイコン通信規格">マイコン/通信規格
&lt;/h3>&lt;p>マイコンにもいくつかの種類がある。個人開発で使用しやすいのはArduinoファミリやESP32ファミリだろうか。今回は&lt;strong>無駄に&lt;/strong>Arduino mega（の、互換機）を採用した。NANOでよい。またESP32によるwifi経由でのDBへのデータの直接投入や、LoRaモジュールを利用した低消費電力長距離通信などもテストしたが、今回は明らかにオーバースペックなので採用していない。マイコンとセンサをそれぞれいい感じに配線する。長期間運用する場合には面倒でもブレッドボードではなく基盤にはんだ付けしてやること。現代においてはブレッドボードと同じようにランドが繋がっている便利な基盤が市販されている。面倒な配線作業は不要だ。&lt;/p>
&lt;h3 id="小型linuxマシン">小型Linuxマシン
&lt;/h3>&lt;p>実は！小型でもLinuxでもなくてもよい。何事にも全力で当たりたいタイプならフルサイズのデスクトップPCを採用しても特に問題ない。しかし、LoRaモジュールやセンサの接続、運用時間の長さ、供給体制などを考えると産業向けのシングルボードコンピュータが無難な選択だろう。&lt;/p>
&lt;p>今回はRaspberry Pi4を採用した。国内ではPi5に給電するための電源が入手しづらいためだ&lt;sup id="fnref:5">&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref">5&lt;/a>&lt;/sup>。また、頻繁なMicroSDへの書き込みは寿命を縮めるため、RAMディスクにデータを蓄積して一定間隔で保存する運用か、組み込み向けグレードのSLCのものを使用するのがよいだろう。両方のアプローチを組み合わせてもよい。よくわからなければ「ドライブレコーダー用」と書いてあるMicroSDカードを選べば最低限なんとかなる。またRaspberry piにはH/W watchdog timerが組み込まれているため、これも忘れずに有効にしておくこと。watchdogを追加してくれるhatも市販されているので、そういったものを追加するのもよい。&lt;/p>
&lt;p>このマシンでは3つのソフトウェアを動作させる。マイコンと通信してセンサのデータを受け取り、データベースに投入するソフトウェア。これは自作する必要がある。加えて、時系列データベースInfluxDBと可視化ツールGrafanaをインストールする。Dockerで動かしても、直接生環境に入れてしまってもよい。今回は面倒だったので生環境に入れた。
それぞれ適切にインストールして適当に連携させる。解説記事はGoogleで検索を行えば無数にヒットし、ChatGPTなりDeepSeekなりに聞けば入力するコマンドまで手取り足取り教えてくれるだろう。かつて先生とすら呼ばれたGoogle検索の威光は消え去り今ではググレカスという単語を聞くことも無くなった。現代社会において驚き屋がエーアイを称賛する鳴き声が朝の時報、検索サービスをググってもカスと揶揄する御宅の鳴き声が夜の時報となっていることからも分かるように実は両者は非常に近い行いでありGoogle検索は2019年にBERTと呼ばれる言語モデルを組み込んでいる検索の劣化は潜在的新規顧客の枯渇による戦略の変化つまり既存ユーザーが更に多く検索しないと有益なサイトにアクセスできなくすればPVが改善するというEnshittificationによる当然の帰結であり技術的な問題ではなく……&lt;/p>
&lt;p>言うまでもないがAPIキーのたぐいは各種サービスに入力しないこと。Gitでプロジェクトを管理しているなら、gitignoreの設定も忘れないように。
マイコンとの通信にはシリアル通信を使用した。距離次第で規格を変えたり何かしら間に挟んだりするが、今回はデフォルトで問題ない。&lt;/p>
&lt;p>すべてがうまくいけば、Grafana上で美しいグラフが見えるはずである。センサーを手で温めたり息を吹きかけてみよう。外部サービスと連携してアラートを飛ばす場合、Grafanaの機能を利用するアプローチとPythonでセンサデータを受け取るタイミングで行うアプローチがある。自分の使用したいサービスが対応しているほうを選ぼう。
&lt;img src="https://blog.gity.co.jp/posts/20250319/iot-shrimp/graph.jpg"
width="4096"
height="3072"
srcset="https://blog.gity.co.jp/posts/20250319/iot-shrimp/graph_hu4365710616871215050.jpg 480w, https://blog.gity.co.jp/posts/20250319/iot-shrimp/graph_hu17883437682169971085.jpg 1024w"
loading="lazy"
alt="開けポンのグラフ"
class="gallery-image"
data-flex-grow="133"
data-flex-basis="320px"
>&lt;/p>
&lt;h3 id="クラウド基盤メインマシン">クラウド基盤、メインマシン
&lt;/h3>&lt;p>センサー群をまとめるマイコン、をまとめる小型Linuxマシン、をまとめるために必要。これを導入する場合、先述のラズパイはIoTゲートウェイないしエッジ機器的な立ち位置になる。強力な回線で接続され給電にも不自由しない、例えば工場のような場所で運用するなら単純な機能に特化させてもよいし、モバイル通信すら難しい山奥のような環境で運用するなら適当な処理を行わせてデータ量を減らしてから通信するようにしてもよい。Raspberry piは非常に強力な処理能力を備えており、物体認識タスクを1fps前後でこなす程度ならお茶の子さいさいである。何にせよ大規模になると種々の制約からセンサから送られるデータを一時的にストックする必要がどうしても出てくる。&lt;/p>
&lt;p>今回は不要だ。&lt;/p>
&lt;h2 id="終わりに">終わりに
&lt;/h2>&lt;p>機械に見守られながらエビはすくすくと育ち、肉眼での視認も難しい稚エビから立派な天ぷらサイズにまでなった。
彼らの知能は驚くほど高く、なんとGITYにたむろして不定期に奇声をあげる迷惑集団&lt;sup id="fnref:6">&lt;a href="#fn:6" class="footnote-ref" role="doc-noteref">6&lt;/a>&lt;/sup>よりも規則正しい生活リズムを有している。人類滅亡の後には覇権を握っていることうけあいである。
人類をとりまく自然環境は日々厳しさを増している。私もここ最近バイオマイクロマシン&lt;sup id="fnref:7">&lt;a href="#fn:7" class="footnote-ref" role="doc-noteref">7&lt;/a>&lt;/sup>による免疫攻撃に苦しんでいる。たぶん来年くらいに滅ぶだろう。
そんな自然環境も鑑みて、次回はいよいよ不安定化する気象状況に左右されず食料を供給する唯一の方法について書いていく。&lt;/p>
&lt;h2 id="注釈">注釈
&lt;/h2>&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>栃木県、群馬県、埼玉県、山梨県、長野県、岐阜県、滋賀県、奈良県を除く。&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>群馬県には太平洋の魚と日本海側の魚が集中するから日本で最もうまいスシが食べられるというのが実際である。&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>LLMの支援も受けていない。原理的にハードと開発環境のバージョン相性とかサイレントな仕様の破壊的変更とか私の配線ミスとかに対応できないためだ。更に言えば、あれには&lt;em>はんだごてを握れない&lt;/em>という重大な欠陥がある。&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:4">
&lt;p>インターネット上の様々な検索窓にクエリを投入して結果を表示するツール。OSINTで使用されるユーティリティ。&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:5">
&lt;p>財団のやつらが電源回路をケチったため5V5Aという変な電圧電流を要求する。普通のPD対応機器で給電すると3V5Aでハンドシェイクして一応動きはする。画像認識タスクあたりで全力を出すとシステムが落ちる。&amp;#160;&lt;a href="#fnref:5" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:6">
&lt;p>彼らは群馬大学投石学部を名乗りジャンク、工具、専門書、きらら系漫画などを持ち込む、フロアの一部を不当占拠する、怪しいゼミを開催する、寸胴鍋で牛丼を煮るなどの悪行を繰り返している。&amp;#160;&lt;a href="#fnref:6" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:7">
&lt;p>花粉。&amp;#160;&lt;a href="#fnref:7" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>GITYがHHKBのタッチ&amp;トライスポットになりました</title><link>https://blog.gity.co.jp/posts/20250212/hhkb/</link><pubDate>Wed, 12 Feb 2025 00:01:04 +0900</pubDate><guid>https://blog.gity.co.jp/posts/20250212/hhkb/</guid><description>&lt;img src="https://blog.gity.co.jp/posts/20250212/hhkb/hhkb.png" alt="Featured image of post GITYがHHKBのタッチ&amp;トライスポットになりました" />&lt;p>こんにちは。山田ハヤオです。&lt;/p>
&lt;p>この度、GITYが株式会社PFUのHHKBの&lt;em>タッチ＆トライスポット&lt;/em>となりました！！&lt;/p>
&lt;h2 id="hhkbとは">HHKBとは
&lt;/h2>&lt;p>HHKBは、正式名称&lt;em>Happy Hacking Keyboard&lt;/em>という株式会社PFUが販売しているキーボードシリーズの総称です。少ないキー数と合理的なキー配列、世界でも数少ない静電容量無接点方式によるキースイッチによって極上のキーボードとして仕上がっています。&lt;/p>
&lt;p>既に高級なキーボードとして確固たる地位を築いており、世界中に多くの愛用者がいます。&lt;/p>
&lt;p>HHKBについてより詳しく知りたい方は、公式サイトに掲載されているこちらをご覧ください。&lt;/p>
&lt;p>&lt;a class="link" href="https://happyhackingkb.com/jp/life/hhkb_life10.html" target="_blank" rel="noopener"
>HHKBを触ったことがない人向けのFAQ 10選 ～筆者がおすすめしたいキーボード！～ | PFU&lt;/a>&lt;/p>
&lt;h2 id="タッチトライスポットとは">タッチ&amp;amp;トライスポットとは
&lt;/h2>&lt;p>タッチ&amp;amp;トライスポットと呼ばれる場所にはHHKBが設置されています。&lt;/p>
&lt;p>提携を結んだ日本中のシェアオフィスやコワーキングスペースがタッチ&amp;amp;トライスポットとして登録されており、様々な種類のHHKBを実際に試すことができます。&lt;/p>
&lt;p>&lt;a class="link" href="https://happyhackingkb.com/jp/showroom/#gunma" target="_blank" rel="noopener"
>Happy Hacking Keyboard | タッチ&amp;amp;トライスポット | PFU&lt;/a>&lt;/p>
&lt;p>上記のページで、日本中のタッチ&amp;amp;トライスポットの写真を見ることができます。&lt;/p>
&lt;h2 id="gityも仲間入りしました">GITYも仲間入りしました‼️
&lt;/h2>&lt;p>そんなタッチ&amp;amp;トライスポットにGITYも参戦することになりました。&lt;/p>
&lt;p>&lt;img src="https://blog.gity.co.jp/posts/20250212/hhkb/hhkb.png"
width="4032"
height="3024"
srcset="https://blog.gity.co.jp/posts/20250212/hhkb/hhkb_hu3792220324477000389.png 480w, https://blog.gity.co.jp/posts/20250212/hhkb/hhkb_hu4196344627220113854.png 1024w"
loading="lazy"
alt="GITYのHHKB"
class="gallery-image"
data-flex-grow="133"
data-flex-basis="320px"
>&lt;/p>
&lt;p>GITYでは以下の機種が設置されており、実際に自分のデバイスと接続して利用することができます。&lt;/p>
&lt;ul>
&lt;li>HHKB Professional HYBRID Type-S 墨 日本語配列&lt;/li>
&lt;li>HHKB Professional HYBRID Type-S 雪 日本語配列&lt;/li>
&lt;li>HHKB Professional HYBRID Type-S 墨 英語配列&lt;/li>
&lt;li>HHKB Professional HYBRID Type-S 雪 英語配列&lt;/li>
&lt;li>HHKB Studio 墨 英語配列&lt;/li>
&lt;li>HHKB Studio 雪 英語配列&lt;/li>
&lt;/ul>
&lt;h2 id="裏話">裏話
&lt;/h2>&lt;p>実はこのタッチ&amp;amp;トライスポットにGITYも参戦できるのでは……？と言い出したのはこの記事の筆者なのでした。&lt;/p>
&lt;p>GITYには英語配列を使っているプログラマーが多い&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>ので、英語配列のラインナップを多めにしてもらいました。&lt;/p>
&lt;p>是非GITYに来て、世界最高峰のキーボードであるHHKBを触ってみてください。&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>自分の周りの人だけかもしれない……&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>プロジェクトダッシュボードSeedsnを支える技術</title><link>https://blog.gity.co.jp/posts/20250116/seedsn-tech/</link><pubDate>Thu, 16 Jan 2025 22:40:28 +0900</pubDate><guid>https://blog.gity.co.jp/posts/20250116/seedsn-tech/</guid><description>&lt;img src="https://blog.gity.co.jp/posts/20250116/seedsn-tech/seedsn.png" alt="Featured image of post プロジェクトダッシュボードSeedsnを支える技術" />&lt;p>こんにちは、GITYでSeedsnを開発している山田ハヤオです。SeedsnはGITYで進行しているプロジェクトや、
これから立ち上げたいプロジェクトを掲示しておき、人と人を繋げていくというプラットフォームです。&lt;/p>
&lt;p>当初このアプリは群馬大学の4年生の先輩たちによって開発されており、現在ではそれを私と私の友人が引き継いで開発を続けています。&lt;/p>
&lt;p>今回はSeedsnの開発に利用されている技術と、現在の問題点についてお話します。&lt;/p>
&lt;h2 id="フロントエンド">フロントエンド
&lt;/h2>&lt;h3 id="採用している主な技術">採用している主な技術
&lt;/h3>&lt;p>フロントエンドではReactのフレームワークであるNext.jsを用いています。キャッシュによる最適化やファイルベースなルーティング等、非常に重厚なフレームワークです。
SeedsnではPagesルーティングを採用し、殆どのコンポーネントがCSRで動作しています。&lt;/p>
&lt;p>UIライブラリにはMUIを用いています。MUIは旧来はMaterial UIと呼ばれており、React上で動作するUIライブラリとして古くから利用されています。
styled-componentの上に構築されており、Googleの提唱するMaterial DesignをReact上で簡単に実装することができます。&lt;/p>
&lt;h3 id="フォーマッタとリンタについて">フォーマッタとリンタについて
&lt;/h3>&lt;p>フォーマッタにはESLint v8系とPrettierを用い、&lt;a class="link" href="https://github.com/prettier/eslint-plugin-prettier" target="_blank" rel="noopener"
>&lt;code>eslint-plugin-prettier&lt;/code>&lt;/a>でESLint経由でPrettierを実行しています。このプラグインは現在は既に非推奨になっているようですが、フォーマットが行われていない部分が一目瞭然になり便利なため未だに利用しています。&lt;/p>
&lt;p>&lt;code>eslint-plugin-prettier&lt;/code>と&lt;code>eslint-config-prettier&lt;/code>の役割の違いや現在のベストプラクティスは以下に記載されています。&lt;/p>
&lt;p>&lt;a class="link" href="https://blog.ojisan.io/prettier-eslint-cli/" target="_blank" rel="noopener"
>Prettier と ESLint の組み合わせの公式推奨が変わり plugin が不要になった | blog.ojisan.io&lt;/a>&lt;/p>
&lt;p>注意するべきは、上記のサイトで記載されているベストプラクティスについてはあくまでも「ESLintとPrettierを組み合わせる際の方法」の話に限定されるものであり、実際の設定ファイルの書き方は推奨されるものではありません。&lt;/p>
&lt;p>現行のESLint v9以降ではFlat Configと呼ばれる新しい設定ファイルの記述方法がデフォルトとなり、従来の&lt;code>json&lt;/code>ファイルを利用した記述方法は廃止されました。
Flat ConfigはECMA Script Modulesを活用した新たな書き方であり、従来の設定でわかりにくかった&lt;code>extends&lt;/code>や&lt;code>plugins&lt;/code>が利用できなくなりました。&lt;/p>
&lt;p>従来までの&lt;code>extends&lt;/code>は記述された文字列を元にESLint側が独自で設定ファイルの依存関係を解決するという形でした。
これはESLint側の実装量が多くなる上、コード上では単なる文字列でしかないため関係の記述の複雑さと柔軟性を低下させるものでした。&lt;/p>
&lt;p>新しいFlat ConfigではES Modulesによる&lt;code>import&lt;/code>文を用いてパッケージから設定ファイルを直にインポートします。これが意味するところは、旧来まではESLintによって独自に行っていた依存関係の解決とインポートをJavaScriptエンジンに委任するということです。&lt;/p>
&lt;p>設定の記述が大きく変わり破壊的変更も多く加えられた結果、Next.jsがFlat Configをサポートするようになったのは最新のNext.js 14になってからでした。
SeedsnではNext.js 13を利用しているため、これらの最新の設定方式を記述することができません。&lt;/p>
&lt;p>リンタのためだけにアプリケーションフレームワークのメジャーバージョンを更新するべきかというと、私は決してその必要はないのではないかと思います。
開発メンバーの多くはNext.js 14で導入された新機能をふんだんに活用するほど精通していませんし、現在のSeedsnに導入するにはそれなりの規模の改修が必要になります。&lt;/p>
&lt;p>現在は&lt;a class="link" href="https://biomejs.dev/" target="_blank" rel="noopener"
>Biome&lt;/a>や&lt;a class="link" href="https://github.com/xojs/xo" target="_blank" rel="noopener"
>XO&lt;/a>といった選択肢も登場しており、今後の動向次第ではこちらに乗り換えることになるかもしれません。&lt;/p>
&lt;h3 id="状態管理">状態管理
&lt;/h3>&lt;p>Seedsnはその性質上、アプリケーションが多くの状態を保持する必要があります。&lt;/p>
&lt;p>初期の頃のSeedsnではContextを用いていたものの、これらの更新による不必要な再レンダリングやコード量の増加等を考慮した結果
&lt;a class="link" href="https://jotai.org/" target="_blank" rel="noopener"
>Jotai&lt;/a>を導入することになりました。
JotaiはRecoilの意思を継いだ状態管理ライブラリであり、ReduxやZustandとは異なり&lt;code>atom&lt;/code>という小さな状態を複数個保持しています。&lt;/p>
&lt;p>SeedsnではJotaiを採用していますが、状態管理ライブラリに大きく依存することを避けるためにAtomをexportせずにカスタムフック内で隠蔽しています。
隠蔽は以下のように行います。例えば、なにかの金額をグローバルに管理するという場合には以下のようになります。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-tsx" data-lang="tsx">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">import&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">useAtom&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">atom&lt;/span> &lt;span class="p">}&lt;/span> &lt;span class="kr">from&lt;/span> &lt;span class="s2">&amp;#34;jotai&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">moneyAtom&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">atom&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">number&lt;/span> &lt;span class="err">|&lt;/span> &lt;span class="na">null&lt;/span>&lt;span class="p">&amp;gt;(&lt;/span>&lt;span class="kc">null&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">export&lt;/span> &lt;span class="kr">const&lt;/span> &lt;span class="nx">useMoney&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">()&lt;/span>&lt;span class="o">:&lt;/span>&lt;span class="kt">number&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">null&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="nx">useAtom&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">moneyAtom&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>各コンポーネントは&lt;code>useMoney&lt;/code>を使い、Jotaiの存在を認知することはありません。&lt;/p>
&lt;p>将来的に状態管理ライブラリに大きな変革が起きた場合やJotaiが利用できなくなった場合等にも容易に対処できるよう、できる限りライブラリへの依存は薄めていく方針です。&lt;/p>
&lt;h3 id="データ取得">データ取得
&lt;/h3>&lt;p>データ取得も同様にJotaiを用いています。Jotaiを採用した大きな理由の一つに&lt;a class="link" href="https://jotai.org/docs/guides/async" target="_blank" rel="noopener"
>Async atom&lt;/a>の存在があります。&lt;/p>
&lt;p>使い方はReact 19における&lt;a class="link" href="https://ja.react.dev/reference/react/use" target="_blank" rel="noopener"
>&lt;code>use&lt;/code>フック&lt;/a>に近く、フック内でデータ取得を行います。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-tsx" data-lang="tsx">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">import&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">atom&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">useAtom&lt;/span> &lt;span class="p">}&lt;/span> &lt;span class="kr">from&lt;/span> &lt;span class="s2">&amp;#34;jotai&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">import&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">APIClient&lt;/span> &lt;span class="p">}&lt;/span> &lt;span class="kr">from&lt;/span> &lt;span class="s2">&amp;#34;@/utils&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">projectsAtom&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">atom&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kr">async&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kr">get&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">api&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nx">APIClient&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="nx">api&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">getProjects&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="nx">res&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ok&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">null&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="nx">res&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">json&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">export&lt;/span> &lt;span class="kr">const&lt;/span> &lt;span class="nx">useProjects&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">()&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="nx">useAtomValue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">projectsAtom&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>実際にはもう少し要件が複雑になるため同様のコードというわけではないのですが……&lt;/p>
&lt;p>やはり先程も言った通り、ライブラリへの依存を抑えて書き換えやすくするということに焦点を当てています。
フロントエンドの業界は流行の変化が激しいので、それに追従できる形のコーディングを心がけています。&lt;/p>
&lt;p>また、APIClientも注目してほしい部分です。後述するバックエンドサーバーと通信を行うために記述したクライアントラッパーであり、シンプルな実装ながら非常に実用的です。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-ts" data-lang="ts">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">interface&lt;/span> &lt;span class="nx">TypedResponse&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">T&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> &lt;span class="kr">extends&lt;/span> &lt;span class="nx">Response&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">json&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">Promise&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">T&lt;/span>&lt;span class="p">&amp;gt;;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">type&lt;/span> &lt;span class="nx">PromiseRes&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">T&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">Promise&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">TypedResponse&lt;/span>&lt;span class="err">&amp;lt;&lt;/span>&lt;span class="na">T&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">export&lt;/span> &lt;span class="kr">class&lt;/span> &lt;span class="nx">BaseClient&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="cm">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * @param baseUrl APIのベースURL
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">private&lt;/span> &lt;span class="kr">readonly&lt;/span> &lt;span class="nx">baseUrl&lt;/span>: &lt;span class="kt">string&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">constructor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">baseUrl&lt;/span>: &lt;span class="kt">string&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">this&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">baseUrl&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">baseUrl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">fetch&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">T&lt;/span>&lt;span class="p">&amp;gt;(&lt;/span>&lt;span class="nx">endpoint&lt;/span>: &lt;span class="kt">string&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">method&lt;/span>: &lt;span class="kt">string&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">cookie?&lt;/span>: &lt;span class="kt">string&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">body?&lt;/span>: &lt;span class="kt">unknown&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">PromiseRes&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">T&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">fetch&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sb">`&lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="k">this&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">baseUrl&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">/api/&lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">endpoint&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">`&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">headers&lt;/span>: &lt;span class="kt">new&lt;/span> &lt;span class="nx">Headers&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Content-Type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;application/json&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">Cookie&lt;/span>: &lt;span class="kt">cookie&lt;/span> &lt;span class="o">??&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">method&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">body&lt;/span>: &lt;span class="kt">JSON.stringify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">body&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">credentials&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;include&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">get&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">T&lt;/span>&lt;span class="p">&amp;gt;(&lt;/span>&lt;span class="nx">endpoint&lt;/span>: &lt;span class="kt">string&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">cookie?&lt;/span>: &lt;span class="kt">string&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">PromiseRes&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">T&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="k">this&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">fetch&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">endpoint&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;GET&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">cookie&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">export&lt;/span> &lt;span class="kr">class&lt;/span> &lt;span class="nx">APIClient&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">private&lt;/span> &lt;span class="kr">readonly&lt;/span> &lt;span class="nx">backend&lt;/span>: &lt;span class="kt">BaseClient&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">private&lt;/span> &lt;span class="kr">readonly&lt;/span> &lt;span class="nx">cookie&lt;/span>: &lt;span class="kt">string&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="cm">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * @param cookie ユーザーのCookie
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">constructor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">cookie&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">this&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">backend&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nx">BaseClient&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;https://example.com&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">this&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">cookie&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">cookie&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">getProjects&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">()&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">PromiseRes&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="p">{&lt;/span> &lt;span class="nx">projects&lt;/span>: &lt;span class="kt">Project&lt;/span>&lt;span class="p">[]&lt;/span> &lt;span class="p">}&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="o">=&amp;gt;&lt;/span> &lt;span class="k">this&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">backend&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="kr">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;projects&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">this&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">cookie&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;code>fetch&lt;/code>APIを型定義と共にラップしたBaseClientと、実際のエンドポイントが記述されたAPIClientで構成されています。
これにより各コンポーネントでAPIのURLを直に記述することなくサーバーのエンドポイントを叩くことができます。&lt;/p>
&lt;p>この実装の現在の課題は型定義です。fetchのデコード結果の&lt;code>any&lt;/code>型を強引に書き換える形で型定義を実現しているのですが、実際にサーバーから受け取った値をチェックしているわけではないので型安全とは言えません。&lt;/p>
&lt;p>Tanstack Queryの&lt;code>queryFn&lt;/code>としてAPIClientを指定し、Zodでバリデーションを行うというのが理想でしょう。
運の良いことにJotaiとTanstack Queryを統合するライブラリが公式によって紹介されています。&lt;/p>
&lt;p>&lt;a class="link" href="https://jotai.org/docs/extensions/query" target="_blank" rel="noopener"
>Query — Jotai, primitive and flexible state management for React&lt;/a>&lt;/p>
&lt;p>今後、データフェッチでの型安全性が重要視される場合には導入することになるかもしれません。
Jotaiは比較的薄いライブラリであるため、こういった複数のライブラリ同士での組み合わせが行いやすいのも特徴です。&lt;/p>
&lt;h3 id="今後の展望">今後の展望
&lt;/h3>&lt;p>フロントエンド業界は今後ますますRSCの世界が中心になっていくでしょう。そうなった際にstyled-componentは足枷になる可能性があります。&lt;/p>
&lt;p>パフォーマンスにどの程度重点を置いて開発するかというのは規模感や技術力に依存するのでしょうが、果たしてSeedsnの規模はRSCを念頭に置く必要があるのかどうか。
残念ながら実践経験の少ない私にはそれらを見極める方法がありません。GITYにいるエンジニアさんにはよく「そこまで気にしなくてもいいんじゃない?」と言われますが、
効率やパフォーマンスを強く意識してしまうが故に開発速度やプライオリティを軽視しがちなのは私の課題なのではないかと思います。&lt;/p>
&lt;h2 id="バックエンド">バックエンド
&lt;/h2>&lt;h3 id="利用している技術やサービス">利用している技術やサービス
&lt;/h3>&lt;p>バックエンドにはGolangとバックエンドフレームワークであるGinを用いています。&lt;/p>
&lt;p>データベースにはSupabaseを用いており、&lt;a class="link" href="https://github.com/supabase-community/supabase-go" target="_blank" rel="noopener"
>supabase-go&lt;/a>というコミュニティによって開発された
ライブラリを用いて通信を行っています。このライブラリはORMのような重厚なものを利用しておらず、PostgRESTというPostgreSQLのREST APi Wrapperを用いています。&lt;/p>
&lt;p>認証バックエンドにはKeycloakやGoogleを用い、OpenID Connectと呼ばれるOAuth 2を利用したプロトコルを用いて認証・認可を行っています。
&lt;a class="link" href="https://github.com/coreos/go-oidc" target="_blank" rel="noopener"
>go-oidc&lt;/a>はOpenID ConnectをGolangで実装するためのライブラリであり、Fedora CoreOSのチームが開発してます。
Golang準公式の&lt;a class="link" href="https://github.com/golang/oauth2" target="_blank" rel="noopener"
>oauth2&lt;/a>を拡張する形で利用することができます。&lt;/p>
&lt;h3 id="データベースとの通信について">データベースとの通信について
&lt;/h3>&lt;p>&lt;a class="link" href="https://github.com/supabase-community/supabase-go" target="_blank" rel="noopener"
>supabase-go&lt;/a>ではSQL文のような感覚でメソッドチェーンを記述しSupabaseからデータを取得できます。
准公式という扱いらしく、コミュニティ主導によって開発されているライブラリのようです。
その実装は&lt;a class="link" href="https://github.com/supabase-community/postgrest-go" target="_blank" rel="noopener"
>postgrest-go&lt;/a>を薄くラップしたもので、クエリで実際に記述しているもののほとんどの実装はこちらのライブラリに書かれています。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">func&lt;/span> &lt;span class="nf">GetProjects&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">([]&lt;/span>&lt;span class="nx">Project&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">error&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">var&lt;/span> &lt;span class="nx">projects&lt;/span> &lt;span class="p">[]&lt;/span>&lt;span class="nx">Project&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">var&lt;/span> &lt;span class="nx">resp&lt;/span> &lt;span class="kd">interface&lt;/span>&lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">_&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">client&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">From&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">projectListTable&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nf">Select&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;*&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kc">false&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nf">ExecuteTo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="nx">resp&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="kc">nil&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nx">projects&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">err&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// convert to JSON byte array
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">jsonData&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">json&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Marshal&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">resp&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="kc">nil&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nx">err&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// unmarshal
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nx">json&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Unmarshal&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">jsonData&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="nx">projects&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="kc">nil&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nx">err&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nx">projects&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kc">nil&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>上記のプロジェクト一覧を取得する際のコードの一部分です。
&lt;code>json&lt;/code>ライブラリで構造体にマッピングしてあげるだけなので、取得されたデータの扱いはhttpリクエストの結果を処理するのと全く同様になります。&lt;/p>
&lt;p>軽量でSQLに近い書き方ができるので学習コストが低い一方で、ORMやスキーマ定義を行っていないので構造変更が起きた際のマイグレーションに非常に苦労します。
こちらも規模の小さいアプリケーションには非常に向いていますが、今後規模が拡大していくとなった際に課題になりそうな部分です。&lt;/p>
&lt;p>またこちらもフロントエンドと同じくGolangの型定義以上のバリデーションを行っていないため、安全なコードであると言い切ることはできません。
これらは早急に何かしらのバリデーションライブラリを用いてチェックを実装したいところです。&lt;/p>
&lt;h2 id="終わり">終わり
&lt;/h2>&lt;p>Seedsnは群馬大学の情報学部の学生が勉強しながら開発をしているアプリケーションです。
Next.js等のモダンなフレームワークを採用し、高速かつ少ないランニングコストで実行できます。&lt;/p>
&lt;p>一方で、比較的新しい技術を積極的に用いているとはいえ最新とは言い難い状況です。
更に、バリデーションや型チェック等の細かな部分の粗が目立ってしまっているのも現実です。&lt;/p>
&lt;p>開発当初はページ全体のレンダリングが停止してしまうようなバグが頻発し不安定だった時期もありました。
今後はモダンな技術を採用しつつも安定性や安全性に重点を置いたアップデートを行っていきたいです。&lt;/p>
&lt;p>またSeedsnで大きな採用技術の変更や、開発で大きな壁に遭遇した際にはブログに書こうと思います。
最後まで読んでいただきありがとうございました。&lt;/p></description></item><item><title>GITYブログはじめました</title><link>https://blog.gity.co.jp/posts/20250106/hello-world/</link><pubDate>Mon, 06 Jan 2025 18:03:25 +0900</pubDate><guid>https://blog.gity.co.jp/posts/20250106/hello-world/</guid><description>&lt;p>こんにちは、GITYで活動している学生の山田ハヤオです。&lt;/p>
&lt;p>GITYには様々な活動をしている学生が多くおり、もちろん情報学部の学生もたくさんいます。&lt;/p>
&lt;p>こういった学生がもっと気軽に専門的な内容を発信できるよう、(午前6時にふと思いついて)このブログを立ち上げました。&lt;/p>
&lt;h2 id="目的">目的
&lt;/h2>&lt;p>大変ありがたいことに、GITYには非常に多くの学生と専門的な知識を持った大人が集まって日々活動しています。
その中にはCATENASに直接関わっている方々もいれば、そうでない人々もいるでしょう。&lt;/p>
&lt;p>せっかくそういった専門性があるコミュニティが形成されているのですから、それをアウトプットしないのは非常に勿体ないことだなと感じました。
アウトプットを行うことでコミュニティ全体の活性化が行われるとともに、GITYという場所がどういったことをしているのかを発信することで
外部の人に知ってもらえたら良いなと思っています。&lt;/p>
&lt;h2 id="記事を書きたい">記事を書きたい
&lt;/h2>&lt;p>&lt;a class="link" href="https://blog.gity.co.jp/how-to-write" >記事の書き方&lt;/a>をご覧ください。&lt;/p></description></item></channel></rss>