<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>開発 – AichiLog</title>
	<atom:link href="https://aichi.blog/tag/%E9%96%8B%E7%99%BA/feed/" rel="self" type="application/rss+xml" />
	<link>https://aichi.blog</link>
	<description>学びて富み　富みて学ぶ</description>
	<lastBuildDate>Sun, 17 Aug 2025 04:42:07 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://aichi.blog/wp-content/uploads/2021/12/cropped-915AB649-D1E9-4810-9658-CB8CE1B605FD.JPEG-2-32x32.jpeg</url>
	<title>開発 – AichiLog</title>
	<link>https://aichi.blog</link>
	<width>32</width>
	<height>32</height>
</image> 
<atom:link rel="hub" href="https://pubsubhubbub.appspot.com"/>
<atom:link rel="hub" href="https://pubsubhubbub.superfeedr.com"/>
<atom:link rel="hub" href="https://websubhub.com/hub"/>
<atom:link rel="self" href="https://aichi.blog/tag/%E9%96%8B%E7%99%BA/feed/"/>
	<item>
		<title>アプリ開発で失敗しない！アイデアを検証する 3 ステップフレームワーク</title>
		<link>https://aichi.blog/app-idea-validation/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=app-idea-validation</link>
		
		<dc:creator><![CDATA[愛知郎]]></dc:creator>
		<pubDate>Sun, 17 Aug 2025 04:36:28 +0000</pubDate>
				<category><![CDATA[個人開発]]></category>
		<category><![CDATA[アプリ開発]]></category>
		<category><![CDATA[チェックポイント]]></category>
		<category><![CDATA[開発]]></category>
		<guid isPermaLink="false">https://aichi.blog/app-idea-validation/</guid>

					<description><![CDATA[<p>「アプリ開発をしたけど、全くユーザーが集まらなかった…」 そんな失敗談は珍しくありません。実際、90%のアプリは「誰も欲しくないものを作ってしまう」ことが原因で失敗しています。 そこで本記事では、アプリ開発初心者やスター [&#8230;]</p>
<p>The post <a href="https://aichi.blog/app-idea-validation/">アプリ開発で失敗しない！アイデアを検証する 3 ステップフレームワーク</a> first appeared on <a href="https://aichi.blog">AichiLog</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>「アプリ開発をしたけど、全くユーザーが集まらなかった…」<br />
そんな失敗談は珍しくありません。実際、<strong>90%のアプリは「誰も欲しくないものを作ってしまう」ことが原因で失敗</strong>しています。</p>
<p>そこで本記事では、アプリ開発初心者やスタートアップの方に向けて、<strong>開発前にアイデアを検証できる「3 ステップフレームワーク」</strong>を解説します。</p>
<p>この方法を使えば、半年や 1 年かけて無駄な開発をする前に、<strong>数週間で「本当に需要があるか」を確認</strong>できます。</p>
<p>
  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-2" checked><label class="toc-title" for="toc-checkbox-2">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">アプリ開発が失敗する最大の理由</a></li><li><a href="#toc2" tabindex="0">アプリアイデア検証の 3 ステップ</a><ol><li><a href="#toc3" tabindex="0">ステップ 1：市場規模の分析（マーケットサイズ）</a></li><li><a href="#toc4" tabindex="0">ステップ 2：課題（Problem）の妥当性を確認</a></li><li><a href="#toc5" tabindex="0">ステップ 3：ソリューションのテスト（MVP 検証）</a></li></ol></li><li><a href="#toc6" tabindex="0">検証の成功基準</a></li><li><a href="#toc7" tabindex="0">アプリ検証に役立つツール</a></li><li><a href="#toc8" tabindex="0">レッドフラグ（要注意サイン）</a></li><li><a href="#toc9" tabindex="0">検証後のアクション</a></li><li><a href="#toc10" tabindex="0">まとめ：失敗しないアプリ開発の秘訣</a></li><li><a href="#toc11" tabindex="0">参考文献</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">アプリ開発が失敗する最大の理由</span></h2>
</p>
<p>多くの人がやってしまうのが、<strong>「自分の欲しいもの＝みんなも欲しいもの」</strong>と考えてしまうことです。</p>
<ul>
<li>需要がない</li>
<li>競合が強すぎる</li>
<li>お金を払うユーザーがいない</li>
</ul>
<p>こうした理由でせっかくのアイデアも失敗に終わります。</p>
<p>では、どうやって失敗を防ぐのか？<br />
答えはシンプルで、<strong>作る前に「本当に必要か」をテストすること</strong>です。</p>
<p><h2><span id="toc2">アプリアイデア検証の 3 ステップ</span></h2>
</p>
<p><h3><span id="toc3">ステップ 1：市場規模の分析（マーケットサイズ）</span></h3>
</p>
<p>アプリ開発でまず確認すべきは「市場の大きさ」です。</p>
<ul>
<li><strong>B2C アプリ（消費者向け）</strong></li>
</ul>
<p>  → 潜在ユーザー数が 1,000 万人以上（実際に使うのは 1%と仮定）</p>
<ul>
<li><strong>B2B アプリ（企業向け）</strong></li>
</ul>
<p>  → 10 万社以上の企業をターゲットにできるか</p>
<p>さらに競合調査も重要です。</p>
<ul>
<li>競合が全くいない → 需要がない可能性</li>
<li>競合が多すぎる → 差別化ポイントが必要</li>
</ul>
<p>&#x1f449; <strong>アプリのレビューを調べると、ユーザーの不満や改善点が見つかります。</strong></p>
<p><h3><span id="toc4">ステップ 2：課題（Problem）の妥当性を確認</span></h3>
</p>
<p>「問題はあるけど、お金を払うほどではない」ケースは意外に多いです。</p>
<p><h4>課題認識をチェックする方法</h4>
</p>
<ul>
<li><strong>Google トレンド</strong>で検索需要を確認</li>
<li><strong>SNS や掲示板</strong>でユーザーの不満を探す</li>
<li><strong>競合アプリの口コミ</strong>を分析</li>
</ul>
<h4>支払い意欲をチェックする方法</h4>
</p>
<ul>
<li>B2C → アンケートで「いくらなら払うか」を調査</li>
<li>B2B → 業界のソフトウェア予算をリサーチ</li>
</ul>
<p>&#x1f449; <strong>「困っている」だけでなく「解決にお金を払うか」が重要です。</strong></p>
<p><h3><span id="toc5">ステップ 3：ソリューションのテスト（MVP 検証）</span></h3>
</p>
<p>アプリを作る前に、<strong>小さな実験</strong>で需要を確認します。</p>
<p><h4>ランディングページテスト</h4>
</p>
<ul>
<li>アプリの概要・料金を紹介するページを作成</li>
<li>登録フォームを設置</li>
<li>SNS やコミュニティにシェアして反応を見る</li>
</ul>
<h4>ユーザーインタビュー</h4>
</p>
<ul>
<li>最低 10 人に直接ヒアリング</li>
<li>今はどう解決しているか？</li>
<li>お金を払ってでも解決したいか？</li>
<li>β テスターとして使いたいか？</li>
</ul>
<h2><span id="toc6">検証の成功基準</span></h2>
</p>
<p>検証を通して、以下の基準を満たせば次に進む価値があります。</p>
<ul>
<li>LP のコンバージョン率：5%以上</li>
<li>登録者数：100 人以上</li>
<li>インタビューで 10 人中 7 人が前向き</li>
<li>成功している競合が 3 社以上存在</li>
<li>市場規模が十分にある</li>
</ul>
<h2><span id="toc7">アプリ検証に役立つツール</span></h2>
</p>
<ul>
<li><strong>Google Trends</strong>：検索需要の確認</li>
<li><strong>AppAnnie / SensorTower</strong>：競合アプリの DL 数・収益調査</li>
<li><strong>Facebook Ads Manager</strong>：市場規模の推定</li>
<li><strong>Tally.so</strong>：アンケート作成</li>
<li><strong>Calendly</strong>：ユーザーインタビューの調整</li>
</ul>
<h2><span id="toc8">レッドフラグ（要注意サイン）</span></h2>
</p>
<p>以下に当てはまる場合は、アプリ開発を進める前に見直しが必要です。</p>
<ul>
<li>ユーザーが課題を認識していない</li>
<li>既存の解決策に満足している</li>
<li>顧客獲得コストが高すぎる</li>
<li>季節限定・一回きりの利用しか見込めない</li>
<li>収益モデルが成立しない</li>
</ul>
<h2><span id="toc9">検証後のアクション</span></h2>
</p>
<ul>
<li><strong>成功した場合</strong></li>
</ul>
<ul>
<li>最小限の機能で MVP をリリース</li>
<li>最初の 10 人の有料ユーザーを獲得</li>
<li>フィードバックを元に改善</li>
</ul>
<ul>
<li><strong>失敗した場合</strong></li>
</ul>
<ul>
<li>ターゲット市場を変える</li>
<li>解決策を見直す</li>
<li>新しいアイデアを試す</li>
</ul>
<h2><span id="toc10">まとめ：失敗しないアプリ開発の秘訣</span></h2>
</p>
<p>アプリ開発で失敗する最大の原因は「需要がないものを作ること」です。</p>
<p>そのためには、</p>
<p>1. 市場規模を調べる<br />
2. 課題の妥当性を確認する<br />
3. ソリューションをテストする</p>
<p>この<strong>3 ステップ検証フレームワーク</strong>を実践することで、リスクを最小化できます。</p>
<p>&#x1f449; <strong>数週間の検証で方向性を決めることで、半年や 1 年を無駄にせず、本当に必要とされるアプリを作れるようになります。</strong></p>
<p><h2><span id="toc11">参考文献</span></h2>
</p>
<ul>
<li><a rel="noopener" href="https://amzn.to/3HFA3oa" target="_blank">リーン・スタートアップ　ムダのない起業プロセスでイノベーションを生みだす</a></li>
<li><a rel="noopener" href="https://amzn.to/4mFqG6U" target="_blank">Running Lean 第 3 版 ―リーンキャンバスから始める継続的イノベーションフレームワーク (THE LEAN SERIES)</a></li>
<li><a rel="noopener" href="https://amzn.to/4mFrRDm" target="_blank">SPRINT 最速仕事術――あらゆる仕事がうまくいく最も合理的な方法</a></li>
</ul><p>The post <a href="https://aichi.blog/app-idea-validation/">アプリ開発で失敗しない！アイデアを検証する 3 ステップフレームワーク</a> first appeared on <a href="https://aichi.blog">AichiLog</a>.</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>【保存版】ビジネスアイデアを見極める 7 つのチェックポイント｜起業・新規事業に必須のフレームワーク</title>
		<link>https://aichi.blog/green-flags/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=green-flags</link>
		
		<dc:creator><![CDATA[愛知郎]]></dc:creator>
		<pubDate>Sun, 17 Aug 2025 04:26:43 +0000</pubDate>
				<category><![CDATA[個人開発]]></category>
		<category><![CDATA[アイデア]]></category>
		<category><![CDATA[チェックポイント]]></category>
		<category><![CDATA[ビジネス]]></category>
		<category><![CDATA[開発]]></category>
		<guid isPermaLink="false">https://aichi.blog/green-flags/</guid>

					<description><![CDATA[<p>目次 はじめに1. 明確な問題2. ニーズかウォンツか3. 支払い能力4. 顧客の明確さと到達性5. 成長市場に乗る6. 最初から価値が伝わる7. MVP で早く試せるまとめ｜アイデアを「起業」につなげる 7 つのポイン [&#8230;]</p>
<p>The post <a href="https://aichi.blog/green-flags/">【保存版】ビジネスアイデアを見極める 7 つのチェックポイント｜起業・新規事業に必須のフレームワーク</a> first appeared on <a href="https://aichi.blog">AichiLog</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>
  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-4" checked><label class="toc-title" for="toc-checkbox-4">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">はじめに</a></li><li><a href="#toc2" tabindex="0">1. 明確な問題</a></li><li><a href="#toc3" tabindex="0">2. ニーズかウォンツか</a></li><li><a href="#toc4" tabindex="0">3. 支払い能力</a></li><li><a href="#toc5" tabindex="0">4. 顧客の明確さと到達性</a></li><li><a href="#toc6" tabindex="0">5. 成長市場に乗る</a></li><li><a href="#toc7" tabindex="0">6. 最初から価値が伝わる</a></li><li><a href="#toc8" tabindex="0">7. MVP で早く試せる</a></li><li><a href="#toc9" tabindex="0">まとめ｜アイデアを「起業」につなげる 7 つのポイント</a></li><li><a href="#toc10" tabindex="0">参考文献</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
</p>
<p>「ビジネスアイデアを思いついたけど、本当に売れるのか不安…」<br />
「起業のアイデアがあるけど、市場調査をどうすればいいのか分からない」</p>
<p>そんな悩みを持つ方に向けて、この記事では <strong>スタートアップや新規事業を始める前に確認すべき 7 つのポイント</strong> を紹介します。<br />
このフレームワークを使えば、思いつきの起業アイデアを、実際に収益を生むビジネスアイデアへとブラッシュアップできます。</p>
<p><h2><span id="toc2">1. 明確な問題</span></h2>
</p>
<p>成功するビジネスの出発点は、<strong>顧客の「解決すべき問題」</strong> にあります。<br />
市場調査をするときは、以下の点を確認しましょう。</p>
<ul>
<li>それは「必要不可欠な痛み」か？それとも「あると便利」程度か？</li>
<li>問題は <strong>緊急・頻発・コストが高い</strong> の 3 条件に当てはまるか？</li>
<li>ユーザーはすでに検索・自作ツール・外注で対策しているか？</li>
<li>もし解決策がなくなったら、多くの人が「困る」と感じるか？</li>
</ul>
<p>&#x1f449; <strong>解決すべき痛みがなければ、需要は生まれません。</strong></p>
<p><h2><span id="toc3">2. ニーズかウォンツか</span></h2>
</p>
<p>ビジネスアイデアを考えるときに大事なのは、<strong>人が「欲しい」と言うもの</strong>ではなく、\*\*実際に「行動して解決しようとしているもの」\*\*です。</p>
<ul>
<li>検索・外注・自作ツールで解決しようとしているか？</li>
<li>それとも「こうなったらいいな」と言うだけで行動しないか？</li>
</ul>
<p>&#x1f449; 人は「欲望」ではなく「必要」にお金を払います。</p>
<p><h2><span id="toc4">3. 支払い能力</span></h2>
</p>
<p>どんなに素晴らしい起業アイデアでも、顧客に <strong>支払い能力がなければビジネスは成立しません</strong>。</p>
<ul>
<li>顧客はすでに同じ領域にお金を使っているか？</li>
<li>この問題解決に予算を組んでいるか？</li>
<li>解決すれば「収益アップ」や「コスト削減」につながるか？</li>
</ul>
<p>&#x1f449; <strong>払えない顧客は、ビジネスではなく趣味対象。</strong></p>
<p><h2><span id="toc5">4. 顧客の明確さと到達性</span></h2>
</p>
<p>ビジネスアイデアを収益化するには、<strong>理想の顧客を明確にし、直接リーチできるかどうか</strong> が重要です。</p>
<ul>
<li>顧客像を 1 文で説明できるか？</li>
<li>彼らはどこに集まっているか？（Instagram、YouTube、Reddit、X など）</li>
<li>広告、SEO、SNS マーケティング、コンテンツ発信でアプローチ可能か？</li>
</ul>
<p>&#x1f449; <strong>顧客に届かなければ、どんな商品も売れません。</strong></p>
<p><h2><span id="toc6">5. 成長市場に乗る</span></h2>
</p>
<p>市場調査の際に必ずチェックすべきが、<strong>その市場が成長しているかどうか</strong> です。</p>
<ul>
<li>Google トレンドで需要が右肩上がりか？</li>
<li>AI や規制緩和、新技術で新しいニーズが生まれているか？</li>
<li>大手企業が参入・買収しているか？</li>
</ul>
<p>&#x1f449; <strong>伸びている市場（ブルーオーシャン）に参入することが成功の近道。</strong></p>
<p><h2><span id="toc7">6. 最初から価値が伝わる</span></h2>
</p>
<p>スタートアップや新規事業は、<strong>最初の印象で勝負が決まることも多い</strong> です。</p>
<ul>
<li>すぐに「すごい！」と感じられる体験があるか？</li>
<li>デモやスクショで直感的に伝わるか？</li>
<li>サービスがなくても「ストーリー」だけで魅力を語れるか？</li>
</ul>
<p>&#x1f449; <strong>価値が一瞬で伝わるサービスは、マーケティングが自然に回ります。</strong></p>
<p><h2><span id="toc8">7. MVP で早く試せる</span></h2>
</p>
<p>新規事業を始めるときは「完璧なサービス」を目指すより、<strong>最小限の MVP（Minimum Viable Product）を早く出すこと</strong>が重要です。</p>
<ul>
<li>2 週間以内に AI やノーコードで試作できるか？</li>
<li>ランディングページやウェイトリストから検証できるか？</li>
</ul>
<p>&#x1f449; <strong>傑作ではなく MVP を作り、早く市場でテストすること。</strong></p>
<p><h2><span id="toc9">まとめ｜アイデアを「起業」につなげる 7 つのポイント</span></h2>
</p>
<p>この記事で紹介した <strong>ビジネスアイデアの 7 つのチェックポイント</strong> を振り返ります。</p>
<p>1. 本当に痛い問題を解決しているか？<br />
2. 欲しいものではなく必要なものか？<br />
3. 支払い能力のある顧客がいるか？<br />
4. 顧客像が明確で、リーチできるか？<br />
5. 成長市場に乗れているか？<br />
6. 最初から価値が伝わるか？<br />
7. MVP で早く試せるか？</p>
<p>このフレームワークを使えば、ただの「思いつきの起業アイデア」を、<strong>収益化できる新規事業</strong> へと進化させられます。</p>
<p><h2><span id="toc10">参考文献</span></h2>
</p>
<ul>
<li><a rel="noopener" href="https://amzn.to/3HFA3oa" target="_blank">リーン・スタートアップ　ムダのない起業プロセスでイノベーションを生みだす</a></li>
<li><a rel="noopener" href="https://amzn.to/4mFqG6U" target="_blank">Running Lean 第 3 版 ―リーンキャンバスから始める継続的イノベーションフレームワーク (THE LEAN SERIES)</a></li>
<li><a rel="noopener" href="https://amzn.to/4mFrRDm" target="_blank">SPRINT 最速仕事術――あらゆる仕事がうまくいく最も合理的な方法</a></li>
</ul><p>The post <a href="https://aichi.blog/green-flags/">【保存版】ビジネスアイデアを見極める 7 つのチェックポイント｜起業・新規事業に必須のフレームワーク</a> first appeared on <a href="https://aichi.blog">AichiLog</a>.</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>環境変数の効率的な管理方法：os.Getenv vs os.LookupEnv と github.com/caarlos0/env の活用ガイド</title>
		<link>https://aichi.blog/go-env/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=go-env</link>
		
		<dc:creator><![CDATA[愛知郎]]></dc:creator>
		<pubDate>Wed, 28 May 2025 09:03:44 +0000</pubDate>
				<category><![CDATA[Go]]></category>
		<category><![CDATA[クロージャー]]></category>
		<category><![CDATA[文法]]></category>
		<category><![CDATA[開発]]></category>
		<guid isPermaLink="false">https://aichi.blog/go-env/</guid>

					<description><![CDATA[<p>TL;DR;Go言語での環境変数管理には主にos.Getenvとos.LookupEnvの2つの方法があります。os.Getenvはシンプルでデフォルト値の設定に適しており、os.LookupEnvは環境変数の存在確認が [&#8230;]</p>
<p>The post <a href="https://aichi.blog/go-env/">環境変数の効率的な管理方法：os.Getenv vs os.LookupEnv と github.com/caarlos0/env の活用ガイド</a> first appeared on <a href="https://aichi.blog">AichiLog</a>.</p>]]></description>
										<content:encoded><![CDATA[<p><p class="is-style-big_icon_check">TL;DR;<br />Go言語での環境変数管理には主に<code>os.Getenv</code>と<code>os.LookupEnv</code>の2つの方法があります。<code>os.Getenv</code>はシンプルでデフォルト値の設定に適しており、<code>os.LookupEnv</code>は環境変数の存在確認が必要な場合に使います。より高度な環境変数管理には<code>github.com/caarlos0/env</code>ライブラリが推奨され、構造体タグによる型安全な設定が可能です。テスト時は<code>t.Setenv</code>を使用することで、環境変数の一時的な設定と自動復元が簡単に行えます。</p>
</p>
<p>Go言語の環境変数を取得する方法には<code>os.Getenv</code>と<code>os.LookupEnv</code>の2つの方法があります。</p>
<p>
  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-6" checked><label class="toc-title" for="toc-checkbox-6">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">os.Getenv関数</a></li><li><a href="#toc2" tabindex="0">os.LookupEnv関数</a></li><li><a href="#toc3" tabindex="0">実用的な使い分け例</a></li><li><a href="#toc4" tabindex="0">サードパーティ：github.com/caarlos0/envの使用</a></li><li><a href="#toc5" tabindex="0">基本的な使用方法</a></li><li><a href="#toc6" tabindex="0">os.Getenv/LookupEnvとの比較</a><ol><li><a href="#toc7" tabindex="0">従来の方法（os.Getenv使用）</a></li><li><a href="#toc8" tabindex="0">envライブラリを使用した方法</a></li></ol></li><li><a href="#toc9" tabindex="0">高度な機能の例</a></li><li><a href="#toc10" tabindex="0">実際の使用例（設定ファイル vs 環境変数）</a></li><li><a href="#toc11" tabindex="0">メリットとデメリット</a><ol><li><a href="#toc12" tabindex="0">envライブラリのメリット</a></li><li><a href="#toc13" tabindex="0">envライブラリのデメリット</a></li><li><a href="#toc14" tabindex="0">使い分けの指針</a></li></ol></li><li><a href="#toc15" tabindex="0">環境変数のテスト</a></li><li><a href="#toc16" tabindex="0">t.Setenvメソッドの基本</a></li><li><a href="#toc17" tabindex="0">従来の方法 vs t.Setenv</a><ol><li><a href="#toc18" tabindex="0">従来の方法（非推奨になった理由）</a></li><li><a href="#toc19" tabindex="0">t.Setenvを使った方法（推奨）</a></li></ol></li><li><a href="#toc20" tabindex="0">実践的な使用例</a><ol><li><a href="#toc21" tabindex="0">envライブラリとの組み合わせ</a></li><li><a href="#toc22" tabindex="0">複雑な設定のテスト</a></li></ol></li><li><a href="#toc23" tabindex="0">t.Setenvのメリット</a><ol><li><a href="#toc24" tabindex="0">1. 自動クリーンアップ</a></li><li><a href="#toc25" tabindex="0">2. パラレルテスト対応</a></li><li><a href="#toc26" tabindex="0">3. シンプルなコード</a></li></ol></li><li><a href="#toc27" tabindex="0">注意点とベストプラクティス</a><ol><li><a href="#toc28" tabindex="0">1. Go 1.17以降限定</a></li><li><a href="#toc29" tabindex="0">2. サブテストでの使用</a></li></ol></li><li><a href="#toc30" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">os.Getenv関数</span></h2>
</p>
<ul>
<li><strong>戻り値</strong>: 文字列のみ</li>
<li><strong>動作</strong>: 環境変数が存在しない場合、空文字列<code>""</code>を返す</li>
<li><strong>問題</strong>: 環境変数が存在しないのか、空文字列が設定されているのか区別できない</li>
</ul>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="0">package main

import (
    "fmt"
    "os"
)

func main() {
    // 存在しない環境変数
    value1 := os.Getenv("NON_EXISTENT_VAR")
    fmt.Printf("NON_EXISTENT_VAR: '%s'\n", value1) // 出力: ''

    // 空文字列が設定された環境変数（事前にexport EMPTY_VAR=""で設定）
    value2 := os.Getenv("EMPTY_VAR")
    fmt.Printf("EMPTY_VAR: '%s'\n", value2) // 出力: ''

    // どちらも同じ結果になってしまう
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;0&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h2><span id="toc2">os.LookupEnv関数</span></h2>
</p>
<ul>
<li><strong>戻り値</strong>: <code>(string, bool)</code>の2つの値</li>
<li><strong>動作</strong>: 環境変数の値と、存在するかどうかのbool値を返す</li>
<li><strong>利点</strong>: 環境変数の存在を明確に判定できる</li>
</ul>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="1">package main

import (
    "fmt"
    "os"
)

func main() {
    // 存在しない環境変数
    value1, exists1 := os.LookupEnv("NON_EXISTENT_VAR")
    fmt.Printf("NON_EXISTENT_VAR: value='%s', exists=%t\n", value1, exists1)
    // 出力: NON_EXISTENT_VAR: value='', exists=false

    // 空文字列が設定された環境変数
    value2, exists2 := os.LookupEnv("EMPTY_VAR")
    fmt.Printf("EMPTY_VAR: value='%s', exists=%t\n", value2, exists2)
    // 出力: EMPTY_VAR: value='', exists=true

    // 値が設定された環境変数
    value3, exists3 := os.LookupEnv("PATH")
    fmt.Printf("PATH exists: %t\n", exists3)
    // 出力: PATH exists: true
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;1&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h2><span id="toc3">実用的な使い分け例</span></h2>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="2">package main

import (
    "fmt"
    "os"
)

func getConfig() {
    // os.Getenvの場合：デフォルト値を設定
    dbHost := os.Getenv("DB_HOST")
    if dbHost == "" {
        dbHost = "localhost" // 空文字列でもデフォルト値を使用
    }

    // os.LookupEnvの場合：存在チェック
    dbPort, exists := os.LookupEnv("DB_PORT")
    if !exists {
        dbPort = "5432"
        fmt.Println("DB_PORT not set, using default")
    } else if dbPort == "" {
        fmt.Println("DB_PORT is set but empty!")
        // 空文字列が明示的に設定された場合の処理
    }

    fmt.Printf("DB_HOST: %s, DB_PORT: %s\n", dbHost, dbPort)
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;2&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<ul>
<li><strong><code>os.Getenv</code></strong>: シンプルで、デフォルト値を簡単に設定したい場合に適している</li>
<li><strong><code>os.LookupEnv</code></strong>: 環境変数の存在を明確に判定したい場合や、空文字列と未設定を区別したい場合に適している</li>
</ul>
<p>一般的には、環境変数の存在チェックが重要な場合は<code>os.LookupEnv</code>を、単純にデフォルト値で十分な場合は<code>os.Getenv</code>を使用します。</p>
<p><h2><span id="toc4">サードパーティ：github.com/caarlos0/envの使用</span></h2>
</p>
<p>Web開発をする場合、DBやSaasの接続情報など、複数の環境変数情報が必要になります。</p>
<p>OS パッケージのみを使って環境変数を扱おうとすると環境変数が増えるたびに <code>OS.Getenv</code> 関数を呼び出して変数に値を設定する必要があります。</p>
<p>また、OS パッケージで取得した環境変数の値は string 型なので何らかのスライスや数字型として環境変数を扱いたい場合はそれぞれのパース処理を書く必要も出てきます。</p>
<p>これらを簡略化するためにサードパーティのライブラリ<code>github.com/caarlos0/env</code>を使うと良いです。</p>
<p>このライブラリは構造体のタグを使って環境変数を自動的にマッピングできる便利なツールです。</p>
<p>標準パッケージと比較して次のような優位な点があります。<br />
●<code>Parse</code>関数を一度呼ぶだけで複数の環境変数を読み込むことができる<br />
●構造体への<code>tags</code>で環境変数とフィールドを細付けられる<br />
●<code>string</code>型以外の読み込みができる<br />
●デフォルト値の設定をすることができる<br />
●環境変数未設定の場合は<code>error</code>を返すことを指定できる</p>
<p><h2><span id="toc5">基本的な使用方法</span></h2>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="3">package main

import (
    "fmt"
    "log"

    "github.com/caarlos0/env/v10"
)

type Config struct {
    // 必須の環境変数
    DatabaseURL string `env:"DATABASE_URL,required"`

    // デフォルト値付き
    Port int `env:"PORT" envDefault:"8080"`

    // オプション（デフォルト値なし）
    RedisURL string `env:"REDIS_URL"`

    // bool型
    Debug bool `env:"DEBUG" envDefault:"false"`
}

func main() {
    cfg := Config{}
    if err := env.Parse(&cfg); err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Config: %+v\n", cfg)
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;3&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h2><span id="toc6">os.Getenv/LookupEnvとの比較</span></h2>
</p>
<p><h3><span id="toc7">従来の方法（os.Getenv使用）</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="4">package main

import (
    "fmt"
    "os"
    "strconv"
)

type Config struct {
    DatabaseURL string
    Port        int
    RedisURL    string
    Debug       bool
}

func loadConfigManual() Config {
    cfg := Config{}

    // 必須チェックを手動で行う
    cfg.DatabaseURL = os.Getenv("DATABASE_URL")
    if cfg.DatabaseURL == "" {
        panic("DATABASE_URL is required")
    }

    // 型変換を手動で行う
    portStr := os.Getenv("PORT")
    if portStr == "" {
        cfg.Port = 8080 // デフォルト値
    } else {
        port, err := strconv.Atoi(portStr)
        if err != nil {
            panic("Invalid PORT value")
        }
        cfg.Port = port
    }

    // オプション値
    cfg.RedisURL = os.Getenv("REDIS_URL")

    // bool変換
    debugStr := os.Getenv("DEBUG")
    cfg.Debug = debugStr == "true" || debugStr == "1"

    return cfg
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;4&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h3><span id="toc8">envライブラリを使用した方法</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="5">package main

import (
    "log"
    "github.com/caarlos0/env/v10"
)

type Config struct {
    DatabaseURL string `env:"DATABASE_URL,required"`
    Port        int    `env:"PORT" envDefault:"8080"`
    RedisURL    string `env:"REDIS_URL"`
    Debug       bool   `env:"DEBUG" envDefault:"false"`
}

func loadConfigWithEnv() Config {
    cfg := Config{}
    if err := env.Parse(&cfg); err != nil {
        log.Fatal(err)
    }
    return cfg
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;5&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h2><span id="toc9">高度な機能の例</span></h2>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="6">package main

import (
    "fmt"
    "log"
    "time"

    "github.com/caarlos0/env/v10"
)

type DatabaseConfig struct {
    Host     string `env:"DB_HOST" envDefault:"localhost"`
    Port     int    `env:"DB_PORT" envDefault:"5432"`
    Username string `env:"DB_USER,required"`
    Password string `env:"DB_PASS,required"`
}

type Config struct {
    // ネストした構造体
    Database DatabaseConfig `envPrefix:"DB_"`

    // スライス型
    AllowedHosts []string `env:"ALLOWED_HOSTS" envSeparator:","`

    // 時間型
    Timeout time.Duration `env:"TIMEOUT" envDefault:"30s"`

    // カスタムパーサー
    LogLevel string `env:"LOG_LEVEL" envDefault:"info"`

    // 環境変数の存在チェック
    SecretKey string `env:"SECRET_KEY,required,unset"`
}

func main() {
    cfg := Config{}

    // パースオプション
    opts := env.Options{
        RequiredIfNoDef: true, // デフォルト値がない場合は必須
    }

    if err := env.Parse(&cfg, opts); err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Config: %+v\n", cfg)
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;6&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h2><span id="toc10">実際の使用例（設定ファイル vs 環境変数）</span></h2>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="7">package main

import (
    "fmt"
    "log"
    "os"

    "github.com/caarlos0/env/v10"
)

type AppConfig struct {
    // サーバー設定
    ServerPort int    `env:"SERVER_PORT" envDefault:"8080"`
    ServerHost string `env:"SERVER_HOST" envDefault:"0.0.0.0"`

    // データベース設定
    DatabaseURL      string `env:"DATABASE_URL,required"`
    DatabasePoolSize int    `env:"DB_POOL_SIZE" envDefault:"10"`

    // 外部サービス
    RedisURL    string `env:"REDIS_URL"`
    RedisPrefix string `env:"REDIS_PREFIX" envDefault:"myapp"`

    // セキュリティ
    JWTSecret string `env:"JWT_SECRET,required"`

    // 機能フラグ
    EnableMetrics bool `env:"ENABLE_METRICS" envDefault:"true"`
    EnableDebug   bool `env:"DEBUG" envDefault:"false"`

    // 配列設定
    TrustedProxies []string `env:"TRUSTED_PROXIES" envSeparator:"," envDefault:"127.0.0.1"`
}

func main() {
    // 環境変数の例を設定
    os.Setenv("DATABASE_URL", "postgres://user:pass@localhost/db")
    os.Setenv("JWT_SECRET", "my-secret-key")
    os.Setenv("TRUSTED_PROXIES", "192.168.1.1,10.0.0.1")

    cfg := AppConfig{}
    if err := env.Parse(&cfg); err != nil {
        log.Fatal("設定の読み込みに失敗:", err)
    }

    fmt.Printf("サーバー: %s:%d\n", cfg.ServerHost, cfg.ServerPort)
    fmt.Printf("データベース: %s\n", cfg.DatabaseURL)
    fmt.Printf("デバッグモード: %t\n", cfg.EnableDebug)
    fmt.Printf("信頼できるプロキシ: %v\n", cfg.TrustedProxies)
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;7&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h2><span id="toc11">メリットとデメリット</span></h2>
</p>
<p><h3><span id="toc12">envライブラリのメリット</span></h3>
</p>
<ul>
<li><strong>簡潔なコード</strong>: 構造体タグで設定が完結</li>
<li><strong>型安全</strong>: 自動的な型変換とバリデーション</li>
<li><strong>必須チェック</strong>: <code>required</code>タグで必須項目を指定</li>
<li><strong>デフォルト値</strong>: <code>envDefault</code>で簡単に設定</li>
<li><strong>複雑な型対応</strong>: スライス、時間、カスタム型にも対応</li>
</ul>
<h3><span id="toc13">envライブラリのデメリット</span></h3>
</p>
<ul>
<li><strong>外部依存</strong>: サードパーティライブラリに依存</li>
<li><strong>学習コスト</strong>: タグの記法を覚える必要がある</li>
<li><strong>デバッグ</strong>: エラー時の詳細が分かりにくい場合がある</li>
</ul>
<h3><span id="toc14">使い分けの指針</span></h3>
</p>
<ul>
<li><strong>小規模プロジェクト</strong>: <code>os.Getenv</code> / <code>os.LookupEnv</code> で十分</li>
<li><strong>中〜大規模プロジェクト</strong>: <code>env</code>ライブラリで効率的に管理</li>
<li><strong>設定項目が多い</strong>: <code>env</code>ライブラリが有効</li>
<li><strong>型変換が複雑</strong>: <code>env</code>ライブラリが有効</li>
</ul>
<p>このように、<code>env</code>ライブラリは環境変数の管理を大幅に簡素化し、型安全性を提供する優れたツールです。</p>
<p><h2><span id="toc15">環境変数のテスト</span></h2>
</p>
<p><code>t.Setenv</code>メソッドについて詳しく説明します。</p>
<p>実は、Go 1.17以降では<strong><code>t.Setenv</code>の使用が推奨されています</strong>。</p>
<p><h2><span id="toc16">t.Setenvメソッドの基本</span></h2>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="8">func TestWithSetenv(t *testing.T) {
    // Go 1.17以降で利用可能
    t.Setenv("DATABASE_URL", "postgres://test@localhost/testdb")
    t.Setenv("SERVER_PORT", "8080")

    // テスト終了時に自動的に元の値に復元される
    cfg, err := LoadConfig()
    if err != nil {
        t.Fatal(err)
    }

    if cfg.DatabaseURL != "postgres://test@localhost/testdb" {
        t.Errorf("期待値と異なります")
    }
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;8&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h2><span id="toc17">従来の方法 vs t.Setenv</span></h2>
</p>
<p><h3><span id="toc18">従来の方法（非推奨になった理由）</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="9">func TestOldWay(t *testing.T) {
    // 手動でバックアップと復元
    original := os.Getenv("DATABASE_URL")
    defer func() {
        if original == "" {
            os.Unsetenv("DATABASE_URL")
        } else {
            os.Setenv("DATABASE_URL", original)
        }
    }()

    os.Setenv("DATABASE_URL", "postgres://test@localhost/testdb")

    // テスト実行
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;9&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h3><span id="toc19">t.Setenvを使った方法（推奨）</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="10">func TestNewWay(t *testing.T) {
    // 自動的にバックアップと復元が行われる
    t.Setenv("DATABASE_URL", "postgres://test@localhost/testdb")
    t.Setenv("SERVER_PORT", "8080")
    t.Setenv("DEBUG", "true")

    // テスト実行
    cfg, err := LoadConfig()
    if err != nil {
        t.Fatal(err)
    }

    // アサーション
    if cfg.DatabaseURL != "postgres://test@localhost/testdb" {
        t.Errorf("DATABASE_URL: 期待値=%s, 実際=%s",
            "postgres://test@localhost/testdb", cfg.DatabaseURL)
    }
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;10&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h2><span id="toc20">実践的な使用例</span></h2>
</p>
<p><h3><span id="toc21">envライブラリとの組み合わせ</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="11">package config

import (
    "testing"
    "github.com/caarlos0/env/v10"
)

type AppConfig struct {
    DatabaseURL string   `env:"DATABASE_URL,required"`
    ServerPort  int      `env:"SERVER_PORT" envDefault:"8080"`
    Debug       bool     `env:"DEBUG" envDefault:"false"`
    Features    []string `env:"FEATURES" envSeparator:","`
}

func TestAppConfig(t *testing.T) {
    tests := []struct {
        name     string
        envVars  map[string]string
        expected AppConfig
        wantErr  bool
    }{
        {
            name: "すべての環境変数が設定されている",
            envVars: map[string]string{
                "DATABASE_URL": "postgres://user:pass@localhost/testdb",
                "SERVER_PORT":  "3000",
                "DEBUG":        "true",
                "FEATURES":     "auth,logging,metrics",
            },
            expected: AppConfig{
                DatabaseURL: "postgres://user:pass@localhost/testdb",
                ServerPort:  3000,
                Debug:       true,
                Features:    []string{"auth", "logging", "metrics"},
            },
        },
        {
            name: "デフォルト値が使用される",
            envVars: map[string]string{
                "DATABASE_URL": "postgres://user:pass@localhost/testdb",
            },
            expected: AppConfig{
                DatabaseURL: "postgres://user:pass@localhost/testdb",
                ServerPort:  8080, // デフォルト値
                Debug:       false, // デフォルト値
                Features:    nil,
            },
        },
        {
            name: "必須項目が不足",
            envVars: map[string]string{
                "SERVER_PORT": "3000",
            },
            wantErr: true,
        },
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            // t.Setenvで環境変数を設定
            for key, value := range tt.envVars {
                t.Setenv(key, value)
            }

            cfg := AppConfig{}
            err := env.Parse(&cfg)

            if tt.wantErr {
                if err == nil {
                    t.Error("エラーが期待されていましたが発生しませんでした")
                }
                return
            }

            if err != nil {
                t.Fatalf("予期しないエラー: %v", err)
            }

            // 構造体の比較
            if cfg.DatabaseURL != tt.expected.DatabaseURL {
                t.Errorf("DatabaseURL: 期待値=%s, 実際=%s",
                    tt.expected.DatabaseURL, cfg.DatabaseURL)
            }
            if cfg.ServerPort != tt.expected.ServerPort {
                t.Errorf("ServerPort: 期待値=%d, 実際=%d",
                    tt.expected.ServerPort, cfg.ServerPort)
            }
            if cfg.Debug != tt.expected.Debug {
                t.Errorf("Debug: 期待値=%t, 実際=%t",
                    tt.expected.Debug, cfg.Debug)
            }
        })
    }
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;11&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h3><span id="toc22">複雑な設定のテスト</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="12">func TestComplexConfig(t *testing.T) {
    t.Run("本番環境設定", func(t *testing.T) {
        t.Setenv("ENV", "production")
        t.Setenv("DATABASE_URL", "postgres://prod@prod-db:5432/proddb")
        t.Setenv("REDIS_URL", "redis://redis-cluster:6379")
        t.Setenv("LOG_LEVEL", "warn")
        t.Setenv("RATE_LIMIT", "1000")

        cfg, err := LoadConfig()
        if err != nil {
            t.Fatal(err)
        }

        if cfg.Env != "production" {
            t.Errorf("環境設定が正しくありません: %s", cfg.Env)
        }
    })

    t.Run("開発環境設定", func(t *testing.T) {
        t.Setenv("ENV", "development")
        t.Setenv("DATABASE_URL", "postgres://dev@localhost:5432/devdb")
        t.Setenv("LOG_LEVEL", "debug")
        t.Setenv("HOT_RELOAD", "true")

        cfg, err := LoadConfig()
        if err != nil {
            t.Fatal(err)
        }

        if cfg.Env != "development" {
            t.Errorf("環境設定が正しくありません: %s", cfg.Env)
        }
        if !cfg.HotReload {
            t.Error("開発環境ではホットリロードが有効になっている必要があります")
        }
    })
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;12&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h2><span id="toc23">t.Setenvのメリット</span></h2>
</p>
<p><h3><span id="toc24">1. 自動クリーンアップ</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="13">func TestAutoCleanup(t *testing.T) {
    // テスト前の値
    originalValue := os.Getenv("TEST_VAR")

    t.Setenv("TEST_VAR", "test_value")

    // テスト中
    if os.Getenv("TEST_VAR") != "test_value" {
        t.Error("環境変数が設定されていません")
    }

    // テスト終了後、自動的に元の値に復元される
    // 手動でのクリーンアップは不要
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;13&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h3><span id="toc25">2. パラレルテスト対応</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="14">func TestParallelSafe(t *testing.T) {
    t.Run("テスト1", func(t *testing.T) {
        t.Parallel()
        t.Setenv("TEST_VAR", "value1")

        // このテストは他のテストと並列実行されても安全
        if os.Getenv("TEST_VAR") != "value1" {
            t.Error("値が正しくありません")
        }
    })

    t.Run("テスト2", func(t *testing.T) {
        t.Parallel()
        t.Setenv("TEST_VAR", "value2")

        // 他のテストの環境変数設定に影響されない
        if os.Getenv("TEST_VAR") != "value2" {
            t.Error("値が正しくありません")
        }
    })
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;14&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h3><span id="toc26">3. シンプルなコード</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="15">func TestSimpleCode(t *testing.T) {
    // 従来の方法（煩雑）
    /*
    original := os.Getenv("DB_HOST")
    defer func() {
        if original == "" {
            os.Unsetenv("DB_HOST")
        } else {
            os.Setenv("DB_HOST", original)
        }
    }()
    os.Setenv("DB_HOST", "test-host")
    */

    // t.Setenvを使用（シンプル）
    t.Setenv("DB_HOST", "test-host")
    t.Setenv("DB_PORT", "5432")
    t.Setenv("DB_NAME", "testdb")

    // テスト実行
    config := loadDatabaseConfig()
    if config.Host != "test-host" {
        t.Error("ホスト名が正しくありません")
    }
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;15&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h2><span id="toc27">注意点とベストプラクティス</span></h2>
</p>
<p><h3><span id="toc28">1. Go 1.17以降限定</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="16">//go:build go1.17
// +build go1.17

func TestWithSetenv(t *testing.T) {
    t.Setenv("VAR", "value") // Go 1.17以降でのみ利用可能
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;16&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h3><span id="toc29">2. サブテストでの使用</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="17">func TestSubtests(t *testing.T) {
    t.Run("サブテスト1", func(t *testing.T) {
        t.Setenv("ENV", "test1")
        // この設定はサブテスト終了時に自動クリーンアップされる
    })

    t.Run("サブテスト2", func(t *testing.T) {
        t.Setenv("ENV", "test2")
        // 前のサブテストの設定は影響しない
    })
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;17&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p>簡単にまとめると以下の通りです。</p>
<ul>
<li><strong>Go 1.17以降の標準機能</strong></li>
<li><strong>自動クリーンアップ</strong>でメモリリークやテスト間の干渉を防ぐ</li>
<li><strong>パラレルテスト対応</strong></li>
<li><strong>コードが簡潔</strong>で保守しやすい</li>
<li><strong>エラーが起きにくい</strong>（手動復元の忘れがない）</li>
</ul>
<p>Go 1.17以降を使用している場合は、<code>t.Setenv</code>を積極的に使用することを強く推奨します。</p>
<p><h2><span id="toc30">まとめ</span></h2>
</p>
<p>Goにおける環境変数管理は、シンプルなアプローチから高度なサードパーティライブラリの利用まで幅広く対応しており、プロジェクトの規模や要件に応じて適切な方法を選択することが重要です。<code>os.Getenv</code>や<code>os.LookupEnv</code>は標準ライブラリとして軽量で簡易的な方法を提供する一方で、複雑な型の変換や依存関係の管理が必要な場合には<code>github.com/caarlos0/env</code>のような外部ライブラリが非常に有用です。</p>
<p>特に、環境変数を利用するシステムにおいては、環境変数が正しく設定されていない場合にアプリケーションが予期せぬ挙動をするリスクがあります。そのため、環境変数の存在確認やバリデーションを行う仕組みを導入することが推奨されます。例えば、<code>env</code>ライブラリを使用すれば、環境変数が不足している場合にエラーを返す機能や、デフォルト値の設定、型安全な変換を簡単に実現できます。</p>
<p>また、テスト環境においては、<code>t.Setenv</code>を活用することで環境変数の設定やクリーンアップが効率的に行えるため、テストコードの保守性が向上します。特に、複数の環境で動作するアプリケーションを開発する際には、環境変数を適切に管理することで、設定の切り替えやデプロイがスムーズに行えます。</p>
<p>最終的には、以下のような指針に基づいて環境変数管理の方法を選択すると良いでしょう：</p>
<p>1. 環境変数の数が少なく、単純な設定の場合は<code>os.Getenv</code>や<code>os.LookupEnv</code>を活用する。<br />
2. 型変換やバリデーション、デフォルト値が必要な場合は<code>env</code>ライブラリなどのサードパーティツールを利用する。<br />
3. テスト環境では<code>t.Setenv</code>を活用して環境変数の設定・管理を簡略化する。<br />
4. プロジェクトの規模が拡大する場合は、環境変数管理を一元化し、必要に応じて設定ファイルやシークレット管理ツール（例：HashiCorp Vault、AWS Secrets Manager）と組み合わせる。</p>
<p>適切な手法を選択することで、コードの簡潔さと可読性を保ちながら、安全でスケーラブルなアプリケーションの開発が可能になります。</p><p>The post <a href="https://aichi.blog/go-env/">環境変数の効率的な管理方法：os.Getenv vs os.LookupEnv と github.com/caarlos0/env の活用ガイド</a> first appeared on <a href="https://aichi.blog">AichiLog</a>.</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Go 言語のクロージャーとは？ 無名関数の使い方と注意点</title>
		<link>https://aichi.blog/go-closure/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=go-closure</link>
		
		<dc:creator><![CDATA[愛知郎]]></dc:creator>
		<pubDate>Wed, 28 May 2025 07:39:52 +0000</pubDate>
				<category><![CDATA[Go]]></category>
		<category><![CDATA[クロージャー]]></category>
		<category><![CDATA[文法]]></category>
		<category><![CDATA[開発]]></category>
		<guid isPermaLink="false">https://aichi.blog/go-closure/</guid>

					<description><![CDATA[<p>Go では func(引数…){ … } のように名前を付けずにその場で関数リテラルを作る書き方を「無名関数（anonymous function または closure）」と呼びます。 即席でハンドラーを定義したい 外 [&#8230;]</p>
<p>The post <a href="https://aichi.blog/go-closure/">Go 言語のクロージャーとは？ 無名関数の使い方と注意点</a> first appeared on <a href="https://aichi.blog">AichiLog</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Go では <code>func(引数…){ … }</code> のように<strong>名前を付けずに</strong>その場で関数リテラルを作る書き方を「無名関数（anonymous function または closure）」と呼びます。</p>
<ul>
<li><strong>即席でハンドラーを定義したい</strong></li>
<li><strong>外側の変数を包み込んで（= クロージャ）あとで実行したい</strong></li>
</ul>
<p>  ── そんな時に便利です。</p>
<p>
  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-8" checked><label class="toc-title" for="toc-checkbox-8">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">状態をもつ関数</a></li><li><a href="#toc2" tabindex="0">ミドルウェアの生成：異なるシグネチャ（型）を揃える</a><ol><li><a href="#toc3" tabindex="0">シナリオ：既存のビジネスロジック関数を HTTP ハンドラーとして使いたい場合</a></li><li><a href="#toc4" tabindex="0">既存の関数（シグネチャが合わない）</a></li><li><a href="#toc5" tabindex="0">&#x274c; 無名関数を使用しない場合（コンパイルエラー）</a></li><li><a href="#toc6" tabindex="0">&#x2705; 無名関数を使用した場合（正常動作）</a></li></ol></li><li><a href="#toc7" tabindex="0">より複雑な例：認証付きハンドラー</a><ol><li><a href="#toc8" tabindex="0">既存の関数</a></li><li><a href="#toc9" tabindex="0">&#x274c; 無名関数なしの場合</a></li><li><a href="#toc10" tabindex="0">&#x2705; 無名関数ありの場合</a></li></ol></li><li><a href="#toc11" tabindex="0">ルーチンで無名関数から外部変数を参照することの問題</a><ol><li><a href="#toc12" tabindex="0">1. 競合状態（Race Condition）</a></li><li><a href="#toc13" tabindex="0">2. 変数の予期しない共有</a></li><li><a href="#toc14" tabindex="0">3. スライスの共有による問題</a></li><li><a href="#toc15" tabindex="0">4. Web アプリケーションでの実例</a></li><li><a href="#toc16" tabindex="0">5. チャネルを使った解決方法</a></li></ol></li><li><a href="#toc17" tabindex="0">対策方法一覧</a><ol><li><a href="#toc18" tabindex="0">1. 値渡し</a></li><li><a href="#toc19" tabindex="0">2. 同期プリミティブ</a></li><li><a href="#toc20" tabindex="0">3. アトミック操作</a></li><li><a href="#toc21" tabindex="0">4. チャネル</a></li></ol></li><li><a href="#toc22" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">状態をもつ関数</span></h2>
</p>
<ul>
<li>通常、状態を持たせる時は、構造体を用意し、メソッドを作成する必要がある</li>
<li>ただ、構造体自体に意味がないなら、以下のようにクロージャーを定義・使用することで、冗長な構造体を書かずに済む</li>
</ul>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="0">package main

import "fmt"

// クロージャーは、関数が定義されたときの環境（スコープ）を「覚えている」仕組み
// つまり、関数の外側にある変数にアクセスできる関数のこと
func store() func(int) int {
	// 外側の関数の変数
	sum := 0
	// ↓ クロージャー関数
	return func(i int) int {
		// 内側の関数が外側の変数xを参照している
		sum += i
		return sum
	}
}

func main() {
	// クロージャーを変数に束縛する
	s1 := store()
	s2 := store()

	// クロージャーを呼び出す
	fmt.Println(s1(1))
	fmt.Println(s1(2))
	fmt.Println(s1(3))
	fmt.Println("別のクロージャー")
	fmt.Println(s2(4))
	fmt.Println(s2(5))
	fmt.Println(s2(6))
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;0&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h2><span id="toc2">ミドルウェアの生成：異なるシグネチャ（型）を揃える</span></h2>
</p>
<p>無名関数を使用することで、用意した関数の型とシグネチャが合わない時も無名関数を使用することで、シグネチャを揃えることができます。</p>
<p><h3><span id="toc3">シナリオ：既存のビジネスロジック関数を HTTP ハンドラーとして使いたい場合</span></h3>
</p>
<p><h3><span id="toc4">既存の関数（シグネチャが合わない）</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="1">// 既存のビジネスロジック関数
func calculatePrice(productID string, quantity int) (float64, error) {
    // 商品価格計算のロジック
    basePrice := 100.0
    total := basePrice * float64(quantity)
    return total, nil
}

func getUserProfile(userID string) (string, error) {
    // ユーザープロファイル取得のロジック
    return fmt.Sprintf("User profile for ID: %s", userID), nil
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;1&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h3><span id="toc5">&#x274c; 無名関数を使用しない場合（コンパイルエラー）</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="2">func main() {
    // これはコンパイルエラーになる
    // calculatePriceのシグネチャ: func(string, int) (float64, error)
    // 期待されるシグネチャ: func(http.ResponseWriter, *http.Request)

    http.HandleFunc("/price", calculatePrice) // &#x274c; エラー！
    //                        ^^^^^^^^^^^
    // cannot use calculatePrice (type func(string, int) (float64, error))
    // as type func(http.ResponseWriter, *http.Request) in argument

    http.HandleFunc("/user", getUserProfile) // &#x274c; エラー！
    //                       ^^^^^^^^^^^^^^
    // 同様のエラー
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;2&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h3><span id="toc6">&#x2705; 無名関数を使用した場合（正常動作）</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="3">func main() {
    // 無名関数でシグネチャを合わせる
    http.HandleFunc("/price", func(w http.ResponseWriter, r *http.Request) {
        // HTTPリクエストからパラメータを取得
        productID := r.URL.Query().Get("product_id")
        quantityStr := r.URL.Query().Get("quantity")
        quantity, err := strconv.Atoi(quantityStr)
        if err != nil {
            http.Error(w, "Invalid quantity", http.StatusBadRequest)
            return
        }

        // 既存関数を呼び出し
        price, err := calculatePrice(productID, quantity)
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }

        // レスポンスを返す
        fmt.Fprintf(w, "Total price: %.2f", price)
    })

    http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
        // HTTPリクエストからパラメータを取得
        userID := r.URL.Query().Get("user_id")

        // 既存関数を呼び出し
        profile, err := getUserProfile(userID)
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }

        // レスポンスを返す
        fmt.Fprintln(w, profile)
    })

    http.ListenAndServe(":8080", nil)
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;3&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h2><span id="toc7">より複雑な例：認証付きハンドラー</span></h2>
</p>
<p><h3><span id="toc8">既存の関数</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="4">// 既存の認証関数
func authenticate(username, password string) bool {
    return username == "admin" && password == "secret"
}

// 既存のデータ取得関数
func getSecretData(userID string) (map[string]interface{}, error) {
    return map[string]interface{}{
        "data": "secret information",
        "user": userID,
    }, nil
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;4&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h3><span id="toc9">&#x274c; 無名関数なしの場合</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="5">func main() {
    // これらは全てコンパイルエラー
    http.HandleFunc("/login", authenticate)    // &#x274c; エラー
    http.HandleFunc("/secret", getSecretData)  // &#x274c; エラー
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;5&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h3><span id="toc10">&#x2705; 無名関数ありの場合</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="6">func main() {
    // ログインハンドラー
    http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
        username := r.FormValue("username")
        password := r.FormValue("password")

        // 既存の認証関数を使用
        if authenticate(username, password) {
            fmt.Fprintln(w, "Login successful")
        } else {
            http.Error(w, "Login failed", http.StatusUnauthorized)
        }
    })

    // シークレットデータハンドラー
    http.HandleFunc("/secret", func(w http.ResponseWriter, r *http.Request) {
        userID := r.Header.Get("User-ID")

        // 既存のデータ取得関数を使用
        data, err := getSecretData(userID)
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }

        // JSONレスポンス
        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode(data)
    })

    http.ListenAndServe(":8080", nil)
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;6&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<table class="wp-table">
<thead>
<tr>
<th>項目</th>
<th>無名関数なし</th>
<th>無名関数あり</th>
</tr>
</thead>
<tbody>
<tr>
<td>コンパイル</td>
<td>&#x274c; エラー</td>
<td>&#x2705; 成功</td>
</tr>
<tr>
<td>既存関数の再利用</td>
<td>&#x274c; 不可能</td>
<td>&#x2705; 可能</td>
</tr>
<tr>
<td>HTTP パラメータ処理</td>
<td>&#x274c; 不可能</td>
<td>&#x2705; 可能</td>
</tr>
<tr>
<td>エラーハンドリング</td>
<td>&#x274c; 不可能</td>
<td>&#x2705; 可能</td>
</tr>
<tr>
<td>レスポンス形成</td>
<td>&#x274c; 不可能</td>
<td>&#x2705; 可能</td>
</tr>
</tbody>
</table>
<p><strong>このように、無名関数を使用することで</strong>、既存のビジネスロジックを変更することなく、HTTP ハンドラーとして利用できるようになります。これにより、コードの再利用性と保守性が大幅に向上します。</p>
<p><h2><span id="toc11">ルーチンで無名関数から外部変数を参照することの問題</span></h2>
</p>
<p><h3><span id="toc12">1. 競合状態（Race Condition）</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="7">package main

import (
    "fmt"
    "sync"
    "time"
)

// &#x274c; 問題のあるコード
func badExample() {
    var counter int
    var wg sync.WaitGroup

    for i := 0; i &lt; 1000; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            counter++ // 複数のゴルーチンが同じ変数に同時アクセス
        }()
    }

    wg.Wait()
    fmt.Printf("Counter: %d\n", counter) // 期待値1000だが、実際は不定
}

// &#x2705; 改善されたコード
func goodExample() {
    var counter int
    var wg sync.WaitGroup
    var mu sync.Mutex

    for i := 0; i &lt; 1000; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            mu.Lock()
            counter++ // ミューテックスで保護
            mu.Unlock()
        }()
    }

    wg.Wait()
    fmt.Printf("Counter: %d\n", counter) // 正確に1000
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;7&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h3><span id="toc13">2. 変数の予期しない共有</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="8">// &#x274c; 問題のあるコード：ループ変数の共有
func badLoopExample() {
    var wg sync.WaitGroup

    for i := 0; i &lt; 5; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            fmt.Printf("Value: %d\n", i) // 全て同じ値（5）を出力する可能性
        }()
    }

    wg.Wait()
}

// &#x2705; 改善されたコード：値を明示的に渡す
func goodLoopExample() {
    var wg sync.WaitGroup

    for i := 0; i &lt; 5; i++ {
        wg.Add(1)
        go func(val int) { // パラメータとして渡す
            defer wg.Done()
            fmt.Printf("Value: %d\n", val) // 期待通りの値を出力
        }(i)
    }

    wg.Wait()
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;8&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h3><span id="toc14">3. スライスの共有による問題</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="9">// &#x274c; 問題のあるコード
func badSliceExample() {
    data := []int{1, 2, 3, 4, 5}
    var wg sync.WaitGroup

    for i := 0; i &lt; len(data); i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            data[i] = data[i] * 2 // 競合状態 + インデックス範囲外エラーの可能性
        }()
    }

    wg.Wait()
}

// &#x2705; 改善されたコード
func goodSliceExample() {
    data := []int{1, 2, 3, 4, 5}
    var wg sync.WaitGroup

    for i := 0; i &lt; len(data); i++ {
        wg.Add(1)
        go func(index int, slice []int) { // 値を明示的に渡す
            defer wg.Done()
            slice[index] = slice[index] * 2
        }(i, data)
    }

    wg.Wait()
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;9&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h3><span id="toc15">4. Web アプリケーションでの実例</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="10">// &#x274c; 危険なコード：HTTPハンドラーでの共有変数
func badWebExample() {
    requestCount := 0 // 共有変数

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        go func() {
            requestCount++ // 競合状態
            fmt.Printf("Request count: %d\n", requestCount)
        }()

        fmt.Fprintln(w, "Hello World")
    })
}

// &#x2705; 安全なコード：適切な同期化
func goodWebExample() {
    var requestCount int64

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        go func() {
            atomic.AddInt64(&requestCount, 1) // アトミック操作
            count := atomic.LoadInt64(&requestCount)
            fmt.Printf("Request count: %d\n", count)
        }()

        fmt.Fprintln(w, "Hello World")
    })
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;10&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h3><span id="toc16">5. チャネルを使った解決方法</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="11">// &#x2705; チャネルを使った安全なアプローチ
func channelExample() {
    jobs := make(chan int, 100)
    results := make(chan int, 100)

    // ワーカーゴルーチン
    for w := 1; w &lt;= 3; w++ {
        go func(id int) {
            for job := range jobs {
                result := job * 2 // 外部変数に依存しない
                results &lt;- result
            }
        }(w)
    }

    // ジョブを送信
    for j := 1; j &lt;= 9; j++ {
        jobs &lt;- j
    }
    close(jobs)

    // 結果を受信
    for r := 1; r &lt;= 9; r++ {
        &lt;-results
    }
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;11&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h2><span id="toc17">対策方法一覧</span></h2>
</p>
<p><h3><span id="toc18">1. 値渡し</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="12">go func(val int) {
    // valは各ゴルーチンで独立
}(externalVar)</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;12&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h3><span id="toc19">2. 同期プリミティブ</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="13">var mu sync.Mutex
go func() {
    mu.Lock()
    // 共有リソースへの安全なアクセス
    mu.Unlock()
}()</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;13&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h3><span id="toc20">3. アトミック操作</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="14">go func() {
    atomic.AddInt64(&counter, 1)
}()</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;14&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h3><span id="toc21">4. チャネル</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="15">ch := make(chan int)
go func() {
    ch &lt;- computeValue() // チャネル経由で安全に通信
}()</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;15&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p>ゴルーチンで外部変数を参照する際の主な問題：</p>
<p>1. <strong>データ競合</strong>: 複数のゴルーチンが同じメモリ位置に同時アクセス<br />
2. <strong>予期しない共有</strong>: 変数が意図せず共有される<br />
3. <strong>デバッグの困難さ</strong>: 非決定的な動作により再現が困難</p>
<p>これらの問題を避けるため、<strong>値渡し</strong>、<strong>適切な同期化</strong>、<strong>チャネル</strong>などを使用することが推奨されます。</p>
<p><h2><span id="toc22">まとめ</span></h2>
</p>
<p>Go 言語のクロージャーは、柔軟性と再利用性の高いコードを記述するための強力なツールです。特に、無名関数を使用することで、既存の関数をラップし、新しい文脈やシグネチャに適応させることができます。ただし、クロージャーを使用する際には、外部変数の参照に伴う競合状態や予期しない動作に注意が必要です。</p>
<p>競合状態を防ぐためには、値渡し、同期プリミティブ（ミューテックスやアトミック操作）、またはチャネルを活用することが重要です。これにより、ゴルーチンの安全性が確保され、信頼性の高い並行処理が可能になります。</p>
<p>さらに、HTTP ハンドラーのような現実的なシナリオにおいても、無名関数を活用することで、既存のビジネスロジックを効率的に再利用することができます。</p>
<p>このように、Go 言語のクロージャーは、プログラムの簡潔性と保守性を高めるだけでなく、複雑なタスクをより直感的に実現する手段を提供します。適切な注意を払いながら使用することで、その潜在能力を最大限に引き出すことができるでしょう。</p><p>The post <a href="https://aichi.blog/go-closure/">Go 言語のクロージャーとは？ 無名関数の使い方と注意点</a> first appeared on <a href="https://aichi.blog">AichiLog</a>.</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Go言語のJSON処理｜メモリとストリームの違い・使い分け・実装例まで</title>
		<link>https://aichi.blog/go-json-memory-stream/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=go-json-memory-stream</link>
		
		<dc:creator><![CDATA[愛知郎]]></dc:creator>
		<pubDate>Sun, 27 Apr 2025 04:48:53 +0000</pubDate>
				<category><![CDATA[Go]]></category>
		<category><![CDATA[文法]]></category>
		<category><![CDATA[開発]]></category>
		<guid isPermaLink="false">https://aichi.blog/go-json-memory-stream/</guid>

					<description><![CDATA[<p>Go言語で JSON を扱う際には、標準パッケージ encoding/json を使用するのが一般的です。 このパッケージには、メモリ上で一括変換を行う方法と、ストリームを通じて順次変換する方法の2通りがあります。 まず [&#8230;]</p>
<p>The post <a href="https://aichi.blog/go-json-memory-stream/">Go言語のJSON処理｜メモリとストリームの違い・使い分け・実装例まで</a> first appeared on <a href="https://aichi.blog">AichiLog</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Go言語で JSON を扱う際には、標準パッケージ <code>encoding/json</code> を使用するのが一般的です。<br />
このパッケージには、メモリ上で一括変換を行う方法と、ストリームを通じて順次変換する方法の2通りがあります。</p>
<p>まずはじめに、それぞれの違いを簡単にまとめておきましょう。</p>
<hr>
<p>
  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-10" checked><label class="toc-title" for="toc-checkbox-10">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">メモリ処理とストリーム処理の違い（概要）</a></li><li><a href="#toc2" tabindex="0">エンコードとデコードとは？</a></li><li><a href="#toc3" tabindex="0">メモリで JSON を処理する</a><ol><li><a href="#toc4" tabindex="0">json.Marshal / json.Unmarshal の実装例</a></li><li><a href="#toc5" tabindex="0">メモリ処理の特徴</a></li></ol></li><li><a href="#toc6" tabindex="0">ストリームで JSON を処理する</a><ol><li><a href="#toc7" tabindex="0">json.NewDecoder / json.NewEncoder の実装例</a></li><li><a href="#toc8" tabindex="0">ストリーム処理の特徴</a></li></ol></li><li><a href="#toc9" tabindex="0">メモリ処理とストリーム処理の比較</a></li><li><a href="#toc10" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">メモリ処理とストリーム処理の違い（概要）</span></h2>
</p>
<table class="wp-table">
<thead>
<tr>
<th>特徴</th>
<th>メモリ処理</th>
<th>ストリーム処理</th>
</tr>
</thead>
<tbody>
<tr>
<td>処理方法</td>
<td>データを一括で読み書きする</td>
<td>データを少しずつ読み書きする</td>
</tr>
<tr>
<td>使用関数</td>
<td><code>json.Marshal</code> / <code>json.Unmarshal</code></td>
<td><code>json.Encoder</code> / <code>json.Decoder</code></td>
</tr>
<tr>
<td>対象データ</td>
<td><code>[]byte</code>（メモリ上の全データ）</td>
<td><code>io.Reader</code> / <code>io.Writer</code>（データの流れ）</td>
</tr>
<tr>
<td>適する場面</td>
<td>小〜中規模のデータ、簡単な変換</td>
<td>大規模データ、リアルタイム・逐次処理</td>
</tr>
</tbody>
</table>
<p>このあと、それぞれの方法を具体的に見ていきます。</p>
<hr>
<p><h2><span id="toc2">エンコードとデコードとは？</span></h2>
</p>
<p>GoでJSONを扱う際によく出てくる「エンコード」と「デコード」は、次のような意味です：</p>
<table class="wp-table">
<thead>
<tr>
<th>用語</th>
<th>意味</th>
<th>関数例</th>
</tr>
</thead>
<tbody>
<tr>
<td>エンコード</td>
<td>Goの構造体などのデータをJSON形式の文字列に変換する処理</td>
<td><code>json.Marshal</code> / <code>Encode</code></td>
</tr>
<tr>
<td>デコード</td>
<td>JSON形式の文字列をGoの構造体などのデータに戻す処理</td>
<td><code>json.Unmarshal</code> / <code>Decode</code></td>
</tr>
</tbody>
</table>
<p>たとえば、次のような処理がエンコードとデコードの典型です：</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="0">jsonBytes, _ := json.Marshal(myStruct) // ← エンコード（Go → JSON）
json.Unmarshal(jsonBytes, &myStruct)   // ← デコード（JSON → Go）</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;0&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<hr>
<p><h2><span id="toc3">メモリで JSON を処理する</span></h2>
</p>
<p><h3><span id="toc4">json.Marshal / json.Unmarshal の実装例</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="1">package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func main() {
	// 構造体からJSONへ（エンコード）
	p := Person{Name: "Alice", Age: 30}
	jsonBytes, err := json.Marshal(p)
	if err != nil {
		panic(err)
	}
	fmt.Println("JSON出力:", string(jsonBytes))

	// JSONから構造体へ（デコード）
	var decoded Person
	err = json.Unmarshal(jsonBytes, &decoded)
	if err != nil {
		panic(err)
	}
	fmt.Printf("構造体に戻した結果: %+v\n", decoded)
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;1&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h3><span id="toc5">メモリ処理の特徴</span></h3>
<li>小〜中規模のデータに適している</li>
<li>データ全体を保持してから処理</li>
<li>簡潔で直感的なコードが書ける</li>
<hr>
<p><h2><span id="toc6">ストリームで JSON を処理する</span></h2>
</p>
<p><h3><span id="toc7">json.NewDecoder / json.NewEncoder の実装例</span></h3>
</p>
<div class="hcb_wrap">
<pre class="prism line-numbers language-go" data-lang="go" data-show-lang="1"><code class="language-go" data-hcb-clip="2">package main

import (
	"encoding/json"
	"fmt"
	"os"
)

type Product struct {
	ID    int     `json:"id"`
	Name  string  `json:"name"`
	Price float64 `json:"price"`
}

func main() {
	// ファイルにJSONを書き出す（エンコード）
	f, err := os.Create("product.json")
	if err != nil {
		panic(err)
	}
	defer f.Close()

	encoder := json.NewEncoder(f)
	product := Product{ID: 1, Name: "Notebook", Price: 1299.99}
	if err := encoder.Encode(product); err != nil {
		panic(err)
	}
	fmt.Println("ファイルにJSONを書き出しました")

	// ファイルからJSONを読み込む（デコード）
	f2, err := os.Open("product.json")
	if err != nil {
		panic(err)
	}
	defer f2.Close()

	decoder := json.NewDecoder(f2)
	var p Product
	if err := decoder.Decode(&p); err != nil {
		panic(err)
	}
	fmt.Printf("読み込んだ構造体: %+v\n", p)
}</code></pre>
<p><button class="hcb-clipboard" data-clipboard-target="[data-hcb-clip=&quot;2&quot;]" data-clipboard-action="copy" aria-label="コードをクリップボードにコピーする"></button></div>
<p><h3><span id="toc8">ストリーム処理の特徴</span></h3>
<li>データサイズが大きい場合や継続的に処理したい場合に有効</li>
<li><code>io.Reader</code> / <code>io.Writer</code> を活用</li>
<li>メモリ消費を抑えつつ処理可能</li>
<hr>
<p><h2><span id="toc9">メモリ処理とストリーム処理の比較</span></h2>
</p>
<table class="wp-table">
<thead>
<tr>
<th>項目</th>
<th>メモリ処理 (<code>Marshal</code> / <code>Unmarshal</code>)</th>
<th>ストリーム処理 (<code>Encoder</code> / <code>Decoder</code>)</th>
</tr>
</thead>
<tbody>
<tr>
<td>対象データ</td>
<td>一括データ（<code>[]byte</code>）</td>
<td>順次データ（<code>io.Reader</code> / <code>Writer</code>）</td>
</tr>
<tr>
<td>適するデータ規模</td>
<td>小〜中規模</td>
<td>大規模・連続データ</td>
</tr>
<tr>
<td>メリット</td>
<td>簡単・高速</td>
<td>柔軟・低メモリ</td>
</tr>
</tbody>
</table>
<hr>
<p><h2><span id="toc10">まとめ</span></h2>
</p>
<li><strong>メモリ処理</strong>：<code>json.Marshal</code> / <code>json.Unmarshal</code> は、データを一括で処理するのに適しており、簡潔なコードが書けます。</li>
<li><strong>ストリーム処理</strong>：<code>json.Encoder</code> / <code>json.Decoder</code> は、データを少しずつ処理したい場合に便利で、大規模データやリアルタイム処理に向いています。</li>
<li><strong>エンコード</strong>は「Go構造体 → JSON文字列」、<strong>デコード</strong>は「JSON文字列 → Go構造体」と覚えておきましょう。</li>
<p>処理するデータの大きさや性質に応じて、最適な方法を選ぶことが、Goでの効率的なJSON処理のポイントです。</p><p>The post <a href="https://aichi.blog/go-json-memory-stream/">Go言語のJSON処理｜メモリとストリームの違い・使い分け・実装例まで</a> first appeared on <a href="https://aichi.blog">AichiLog</a>.</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Flutter 製アプリの事例と Flutter vs React Native の将来展望</title>
		<link>https://aichi.blog/flutter-app-examples/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=flutter-app-examples</link>
		
		<dc:creator><![CDATA[愛知郎]]></dc:creator>
		<pubDate>Thu, 27 Feb 2025 09:00:46 +0000</pubDate>
				<category><![CDATA[Flutter]]></category>
		<category><![CDATA[チーム開発]]></category>
		<category><![CDATA[デプロイ]]></category>
		<category><![CDATA[開発]]></category>
		<guid isPermaLink="false">https://aichi.blog/flutter-app-examples/</guid>

					<description><![CDATA[<p>目次 日本国内でよく使われている Flutter 製アプリ海外で人気の Flutter 製アプリFlutter と React Native の今後の勢い比較企業の採用動向市場シェア技術的な優位性開発者の支持率パフォーマ [&#8230;]</p>
<p>The post <a href="https://aichi.blog/flutter-app-examples/">Flutter 製アプリの事例と Flutter vs React Native の将来展望</a> first appeared on <a href="https://aichi.blog">AichiLog</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>
  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-12" checked><label class="toc-title" for="toc-checkbox-12">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">日本国内でよく使われている Flutter 製アプリ</a></li><li><a href="#toc2" tabindex="0">海外で人気の Flutter 製アプリ</a></li><li><a href="#toc3" tabindex="0">Flutter と React Native の今後の勢い比較</a><ol><li><a href="#toc4" tabindex="0">企業の採用動向</a></li><li><a href="#toc5" tabindex="0">市場シェア</a></li><li><a href="#toc6" tabindex="0">技術的な優位性</a></li><li><a href="#toc7" tabindex="0">開発者の支持率</a></li><li><a href="#toc8" tabindex="0">パフォーマンス比較</a></li><li><a href="#toc9" tabindex="0">将来の成長予測</a></li></ol></li></ol>
    </div>
  </div>

<h2><span id="toc1">日本国内でよく使われている Flutter 製アプリ</span></h2>
</p>
<p>Flutter は日本国内でも様々な有名サービスの公式アプリに採用されています。特に以下のような高いダウンロード数・ユーザー数を持つアプリが Flutter で開発されています。</p>
<li><strong>ユニクロ公式アプリ</strong> – 大手アパレル企業ユニクロの公式アプリです。会員バーコードによるポイント管理や最新カタログの閲覧、オンラインストアでの商品購入などが可能です。ユニクロは 2022 年にアプリ 10 周年を迎え、<strong>会員数が 4,000 万</strong>人を突破しました (<a href="https://prtimes.jp/main/html/rd/p/000000029.000068741.html#:~:text=Image">さぁ アプリでお買い物上手に。「ユニクロアプリ 10 周年祭」が 10 月 21 日から開催 | 株式会社ユニクロのプレスリリース</a>)。Flutter の導入により iOS/Android 両方で統一した開発を行っているとされています。</li>
<li><strong>ahamo（アハモ）</strong> – NTT ドコモのオンライン専用料金プラン「ahamo」の公式アプリです。料金プランの契約・管理、データ残量確認、料金支払いなどをシンプルな UI で提供します。ドコモによれば、<strong>ahamo の契約者数は 2023 年 6 月時点で 500 万件</strong>を突破しています (<a href="https://k-tai.watch.impress.co.jp/docs/news/1509372.html#:~:text=NTT%E3%83%89%E3%82%B3%E3%83%A2%E3%81%AF%E3%80%81%E3%82%AA%E3%83%B3%E3%83%A9%E3%82%A4%E3%83%B3%E5%B0%82%E7%94%A8%E6%96%99%E9%87%91%E3%83%96%E3%83%A9%E3%83%B3%E3%83%89%E3%80%8Cahamo%E3%80%8D%E3%81%AE%E5%A5%91%E7%B4%84%E6%95%B0%E3%81%8C%E3%80%816%E6%9C%887%E6%97%A5%E3%81%AB500%E4%B8%87%E5%A5%91%E7%B4%84%E3%82%92%E7%AA%81%E7%A0%B4%E3%81%97%E3%81%9F%E3%81%93%E3%81%A8%E3%82%92%E7%99%BA%E8%A1%A8%E3%81%97%E3%81%9F%E3%80%82%E7%AA%81%E7%A0%B4%E3%82%92%E8%A8%98%E5%BF%B5%E3%81%97%E3%81%9F%E3%82%AD%E3%83%A3%E3%83%B3%E3%83%9A%E3%83%BC%E3%83%B3%E3%82%82%E5%AE%9F%E6%96%BD%E3%81%95%E3%82%8C%E3%82%8B%E3%80%82">ドコモ、「ahamo」の契約数が 500 万を突破 &#8211; ケータイ Watch</a>)。大規模ユーザー向けサービスながら Flutter により高いパフォーマンスと安定性を実現しています (<a href="https://springsapps.com/knowledge/flutter-vs-react-native-in-2024#:~:text=In%20terms%20of%20performance%2C%20Flutter,its%20performance%20compared%20to%20Flutter">Flutter vs React Native in 2025 &#8211; Springs</a>)。</li>
<li><strong>スシロー公式アプリ</strong> – 回転寿司チェーン最大手スシローの公式アプリです。店舗の順番待ち受付や予約、お持ち帰り注文、クーポン配信などを行えます。ユーザー層もファミリー層まで幅広く、<strong>年間アプリ利用者数は約 1,200 万人規模</strong>と推定されています (<a href="https://manamina.valuesccg.com/articles/4011#:~:text=match%20at%20L175%20%E5%B9%B4%E9%96%93%E3%81%AE%E3%82%A2%E3%83%97%E3%83%AA%E8%B5%B7%E5%8B%95%E8%80%85%E6%95%B0%E3%81%AF%E3%81%BB%E3%81%BC%E6%A8%AA%E4%B8%A6%E3%81%B3%E3%81%A7%E3%80%81%E3%81%8F%E3%82%89%E5%AF%BF%E5%8F%B8%E3%81%8C%E3%83%88%E3%83%83%E3%83%97%E3%81%AE1%2C270%E4%B8%87%E4%BA%BA%E3%80%81%E3%82%B9%E3%82%B7%E3%83%AD%E3%83%BC%E3%80%81%E3%81%AF%E3%81%BE%E5%AF%BF%E5%8F%B8%E3%81%8C%E3%81%9D%E3%82%8C%E3%81%AB%E7%B6%9A%E3%81%84%E3%81%A6%20%E3%81%84%E3%81%BE%E3%81%97%E3%81%9F%E3%80%82">スシロー・くら寿司・はま寿司のメニュー、アプリ利用者数、特徴を比較 | ［マナミナ］まなべるみんなのデータマーケティング・マガジン</a>)。Flutter 製のアプリに刷新することで、全ユーザーに滑らかな操作体験を提供しています。</li>
<li><strong>じゃらん（宿・ホテル予約アプリ）</strong> – リクルートが運営する国内旅行予約サービス「じゃらん net」の公式アプリです。宿泊施設や温泉旅館の検索・予約、口コミ閲覧などができます。国内の宿泊予約アプリではダウンロード数トップで、Android 版は<strong>500 万～ 1000 万ダウンロード</strong>に達しています (<a href="https://create-guesthouse.com/ota-apps-download/#:~:text=1%E4%BD%8D%EF%BC%9A%E3%81%98%E3%82%83%E3%82%89%E3%82%93">宿泊予約サイト（ホテル検索）のアプリダウンロード数を、ザックリ調べてみた。 &#8211; ゲストハウスクリエイターズノート</a>)。Flutter 採用により複数プラットフォームで機能を揃え、安定したユーザー体験を実現しています。</li>
<li><strong>メルカリ ハロ</strong> – フリマアプリ大手メルカリが提供するスポットワークマッチングアプリです。好きな時間に最短 1 時間から働ける求人サービスで、登録から応募・勤務開始までスマホで完結します。<strong>メルカリの開発チームはこの「メルカリ ハロ」アプリを Flutter で実装</strong>しており、ホットリロードによる高速な開発サイクルやクロスプラットフォーム対応による効率化を実感したと述べています (<a href="https://pentagon.tokyo/app/6357/#:~:text=%E3%83%A1%E3%83%AB%E3%82%AB%E3%83%AA%E3%81%8C%E9%96%8B%E7%99%BA%E3%81%97%E3%81%9F%E5%A5%BD%E3%81%8D%E3%81%AA%E6%99%82%E9%96%93%E3%81%AB%E6%9C%80%E7%9F%AD1%E6%99%82%E9%96%93%E3%81%8B%E3%82%89%E5%83%8D%E3%81%91%E3%82%8B%E3%80%8C%E3%83%A1%E3%83%AB%E3%82%AB%E3%83%AA%20%E3%83%8F%E3%83%AD%E3%80%8D%E3%81%AF%E3%80%81Flutter%E3%82%92%E6%8E%A1%E7%94%A8%E3%81%97%E3%81%9F%E4%BB%A3%E8%A1%A8%E7%9A%84%E3%81%AA%E4%BA%8B%E4%BE%8B%E3%81%A7%E3%81%99%E3%80%82">Flutter アプリの国内事例 12 選！大手の Flutter 移行も紹介 | 東京のアプリ開発会社</a>)。メルカリという知名度もあり、サービス開始直後から多くのユーザーを集めています。</li>
<p>以上のように、日本国内でも<strong>ユニクロや NTT ドコモ、リクルート、メルカリ</strong>といった大企業が Flutter を採用し、数百万規模のユーザーに利用されるアプリを提供しています。Flutter の高速な UI 描画と安定した動作により、大量のユーザーアクセスにも耐える高品質なサービスが実現されています。</p>
<p><h2><span id="toc2">海外で人気の Flutter 製アプリ</span></h2>
</p>
<p>海外に目を向けると、Flutter はグローバルで数千万規模のユーザーを持つ人気アプリにも採用されています。代表的な例をいくつか挙げます。</p>
<li><strong>Google Pay（GPay）</strong> – Google が提供するデジタル決済アプリです。銀行カードの登録、非接触決済、送金、家計管理など幅広い機能を備えています。2020 年に Flutter でアプリを刷新し、特にインドや米国で展開されています。<strong>Google Pay は世界で 1 億人以上のユーザー</strong>を抱えており (<a href="https://flutter.dev/showcase/google-pay#:~:text=Goal">Flutter Showcase |Google Pay</a>)、Flutter への移行によりコード量を 35%削減し、開発効率を 70%向上させました (<a href="https://flutter.dev/showcase/google-pay#:~:text=%23%2070">Flutter Showcase |Google Pay</a>)。クロスプラットフォーム化で機能リリースのスピードアップと地域展開の迅速化に成功した事例です。</li>
<li><strong>Alibaba Xianyu（閑魚）</strong> – 中国 Alibaba（阿里巴巴）が運営するフリマアプリです。不要品の売買プラットフォームとして、中国国内で非常に大規模に利用されています。<strong>Xianyu アプリは Flutter 製で、ユーザー数は 5,000 万以上</strong>にのぼります (<a href="https://www.goodfirms.co/blog/flutter-2025-definition-key-trends-statistics#:~:text=,10%20million%20daily%20active%20users">Flutter 2025: Definition, Key Trends, and Statistics</a>)。Alibaba は Flutter 採用により、新機能開発の所要時間を 1 か月から 2 週間に短縮できたと報告しています (<a href="https://flutter.dev/showcase#:~:text=Image%3A%20Alibaba">Showcase &#8211; Flutter apps in production</a>)。Flutter の高いパフォーマンスが大規模ユーザーベースの支えとなった好例です。</li>
<li><strong>Nubank</strong> – 南米ブラジル発のデジタル銀行（フィンテック）サービスです。銀行口座管理や送金、クレジットカード利用管理などをスマホアプリで提供しています。Nubank はクロスプラットフォーム技術を比較検討した末に Flutter を採用し、モバイルアプリを構築しました。その結果、<strong>約 4,800 万人以上のユーザー</strong>にサービスを届ける巨大なデジタル銀行アプリを支えています (<a href="https://www.nomtek.com/blog/flutter-app-examples#:~:text=Nubank">Companies Using Flutter in 2024</a>)。Flutter により機能追加の同時リリースが可能になり、生命保険機能を 3 か月で実装するなど開発スピードも飛躍的に向上しました (<a href="https://www.nomtek.com/blog/flutter-app-examples#:~:text=match%20at%20L504%20speed%20up,taken%20at%20least%20a%20year">Companies Using Flutter in 2024</a>)。</li>
<li><strong>My BMW</strong> – ドイツの自動車メーカー BMW が提供する公式スマートフォンアプリです。車両のリモート操作（施錠・解錠、エアコン制御）、走行データ確認、メンテナンス通知など、車とオーナーを繋ぐ様々な機能を持ちます。以前は iOS と Android で別々に開発され機能差がありましたが、Flutter で統合した新アプリ「My BMW」としてリリースされました。その結果、<strong>世界各国向けに 96 種類のバリアントを含むアプリを素早く展開</strong>でき、毎月数千時間相当の開発効率化を達成しています (<a href="https://www.nomtek.com/blog/flutter-app-examples#:~:text=With%20Flutter%2C%20the%20BMW%20team,thousands%20of%20hours%20every%20month">Companies Using Flutter in 2024</a>) (<a href="https://www.nomtek.com/blog/flutter-app-examples#:~:text=Thanks%20to%20Flutter%2C%20BMW%20deployed,resolved%20after%20migrating%20to%20Flutter">Companies Using Flutter in 2024</a>)。全てのユーザーに一貫した体験を提供し、ブランドイメージ向上にも貢献しています。</li>
<li><strong>Kijiji</strong> – eBay 傘下のカナダ最大級のオンラインマーケットプレイス（分類広告サービス）です。ユーザーは地元の売買情報を投稿・検索でき、日本のメルカリに近いサービスと言えます。Kijiji は老朽化したネイティブアプリの技術的負債を解消するため Flutter への全面移行を決断しました。<strong>月間利用者数は約 1,100 万</strong>に及びますが (<a href="https://www.nomtek.com/blog/flutter-app-examples#:~:text=Kijiji">Companies Using Flutter in 2024</a>)、Flutter 化により<strong>新機能リリースの時間が 50%短縮</strong>され、コード量も 64%削減されました (<a href="https://www.nomtek.com/blog/flutter-app-examples#:~:text=Kijiji%20has%20seen%20tremendous%20success,in%20solving%20technological%20debt%20problems">Companies Using Flutter in 2024</a>)。結果として開発サイクルが大幅に加速し、ユーザー体験も向上しています。</li>
<p>以上のように、<strong>Google、Alibaba、Tencent、BMW、eBay</strong>など世界的企業が Flutter を採用し、数千万規模のユーザーにサービス提供しています。特に金融（Google Pay や Nubank）、EC・マーケットプレイス（Alibaba Xianyu や Kijiji）、IoT/自動車（BMW）といった幅広い分野で Flutter アプリが成功を収めています。これは Flutter の信頼性とスケーラビリティがグローバル水準で証明されていることを示しています (<a href="https://www.goodfirms.co/blog/flutter-2025-definition-key-trends-statistics#:~:text=,10%20million%20daily%20active%20users">Flutter 2025: Definition, Key Trends, and Statistics</a>) (<a href="https://flutter.dev/showcase/google-pay#:~:text=Goal">Flutter Showcase |Google Pay</a>)。</p>
<p><h2><span id="toc3">Flutter と React Native の今後の勢い比較</span></h2>
</p>
<p>次に、クロスプラットフォーム開発の代表的技術である<strong>Flutter と React Native</strong>について、以下の視点で現在の状況と将来の勢いを比較します。各項目について最新のデータや傾向を踏まえ、どちらが今後より成長しそうか予測します。</p>
<p><h3><span id="toc4">企業の採用動向</span></h3>
</p>
<p><strong>Flutter 採用の拡大</strong>: Flutter は 2018 年の正式リリース以降、新規プロジェクトを中心に企業導入が急増しています。先述のように Google や Alibaba をはじめ、金融・旅行・通販など様々な業界の大手が Flutter によるアプリ開発に成功しています。日本国内でもリクルート（スタディサプリ）や DMM.com など<strong>既存ネイティブアプリを Flutter に全面移行した例</strong>も出始めています (<a href="https://pentagon.tokyo/app/6357/#:~:text=%E2%91%A0%E3%82%B9%E3%82%BF%E3%83%87%E3%82%A3%E3%82%B5%E3%83%97%E3%83%AA">Flutter アプリの国内事例 12 選！大手の Flutter 移行も紹介 | 東京のアプリ開発会社</a>)。クロスプラットフォームの効率性と Flutter の表現力に魅力を感じ、新規サービスで Flutter を選定する企業が今後も増えると見られます。</p>
<p><strong>React Native の状況</strong>: React Native（RN）は 2015 年に Facebook が公開して以降、多くの企業で採用されてきました。Facebook 本体や Instagram で部分採用されたほか、米国では<strong>Walmart</strong>や<strong>Bloomberg</strong>、日本でもメルカリ（初期の一部機能）や楽天などが一時期導入していた例があります。しかし近年、Airbnb や Dropbox が RN から撤退したように、ネイティブへの回帰や他フレームワークへの移行もみられます。一方で<strong>Meta 社（旧 Facebook）は現在も React Native を社内主要アプリに活用し続けており、Microsoft も React Native for Windows を開発するなど支援</strong>しています。既存の React Native 資産を持つ企業は引き続き RN をメンテナンスしつつ、新規機能では Flutter を試験採用するケースも出ています。総じて、新規採用という観点では Flutter の方が勢いが強く、RN は既存ユーザー企業による支えが中心になりつつあります。</p>
<p><h3><span id="toc5">市場シェア</span></h3>
</p>
<p><strong>開発者利用シェア</strong>: 世界全体のデベロッパー動向を見ると、Flutter が React Native を上回るシェアを占めています。Statista や JetBrains の調査によれば<strong>2022 ～ 2023 年時点でクロスプラットフォーム開発フレームワーク利用率は Flutter が約 46%、React Native が約 32 ～ 35%</strong>となっており、Flutter が最も人気のフレームワークです (<a href="https://code-b.dev/blog/flutter-vs-react-native#:~:text=Flutter%20%26%20React%20Native%20Compared,Flutter%20for%20their%20app">Flutter &#038; React Native Compared | Best Framework for your Project?</a>) (<a href="https://gist.github.com/tkrotoff/93f5278a4e8df7e5f6928eff98684979#:~:text=2023%20,2023%2Fdevelopment%2F%23mobile">React Native vs Flutter · GitHub</a>)。これは数年前まで先行していた React Native を Flutter が追い抜いたことを示しています。この傾向は 2024 年以降も続いており、Stack Overflow 開発者調査 2023 でも<strong>Flutter 利用率 9.1% vs RN 8.4%</strong>と Flutter が僅かながら上回っています (<a href="https://gist.github.com/tkrotoff/93f5278a4e8df7e5f6928eff98684979#:~:text=2023%20,co%2F2023">React Native vs Flutter · GitHub</a>)。また Google Trends の検索人気でも Flutter への関心度が RN を大きく上回っており (<a href="https://flatirons.com/blog/popularity-of-flutter-vs-react-native-2024/#:~:text=Google%20Trends%20Popularity%20Comparison">Popularity of Flutter vs. React Native in 2025 &#8211; Flatirons</a>)、コミュニティの盛り上がりは Flutter が優勢です。</p>
<p><strong>エコシステム規模</strong>: GitHub 上のスター数でも Flutter は約 15.2 万、React Native は約 10.9 万と差がついています (<a href="https://flatirons.com/blog/popularity-of-flutter-vs-react-native-2024/#:~:text=GitHub%20Stars">Popularity of Flutter vs. React Native in 2025 &#8211; Flatirons</a>)。Flutter 関連の Stack Overflow 質問件数も RN より多く、開発者コミュニティの活動量が高いことが伺えます (<a href="https://flatirons.com/blog/popularity-of-flutter-vs-react-native-2024/#:~:text=Stack%20Overflow%20Questions">Popularity of Flutter vs. React Native in 2025 &#8211; Flatirons</a>)。もっとも React Native も依然多くの開発者に使われており、モバイルクロスプラットフォーム分野では Flutter と RN の二強状態が続いています。市場シェアの観点では<strong>Flutter がこのままリードを広げていく可能性が高い</strong>でしょう。</p>
<p><h3><span id="toc6">技術的な優位性</span></h3>
</p>
<p><strong>Flutter の技術特性</strong>: Flutter は Dart 言語で実装され、ネイティブアプリに<strong>Ahead-of-Time（AOT）コンパイル</strong>されるため、ランタイムに仮想マシンやブリッジを必要としません (<a href="https://springsapps.com/knowledge/flutter-vs-react-native-in-2024#:~:text=In%20terms%20of%20performance%2C%20Flutter,its%20performance%20compared%20to%20Flutter">Flutter vs React Native in 2025 &#8211; Springs</a>)。これにより描画パフォーマンスが高く、60fps 以上のスムーズな UI 描画やアニメーションが可能です。また、Flutter は Skia エンジン上に<strong>独自 UI を描画</strong>する仕組みで、デザインの自由度が非常に高いです。プラットフォーム間で UI の再現性が統一され、Android と iOS で全く同じ見た目・挙動を実現できます。加えて、モバイル以外に Web やデスクトップ、組み込み（Embedded）まで単一コードでターゲットにできる点も技術的優位とされています。</p>
<p><strong>React Native の技術特性</strong>: React Native は JavaScript（または TypeScript）と React を用いて記述し、<strong>各プラットフォームのネイティブ UI コンポーネントを橋渡し（ブリッジ）する</strong>形で描画します。メリットは Web フロントエンド技術（JSX+CSS）がそのままモバイル開発に応用でき、Web エンジニアが参入しやすいことです。ネイティブコンポーネントを使うため iOS/Android 各プラットフォームの標準的な UI を自動で取得でき、見た目が「ネイティブらしい」挙動になります。しかし欠点として、JavaScript からネイティブへの<strong>ブリッジによるオーバーヘッド</strong>があり、複雑な画面でパフォーマンスが低下しやすい点が挙げられます (<a href="https://springsapps.com/knowledge/flutter-vs-react-native-in-2024#:~:text=In%20terms%20of%20performance%2C%20Flutter,its%20performance%20compared%20to%20Flutter">Flutter vs React Native in 2025 &#8211; Springs</a>)（Meta は新アーキテクチャでこの問題の改善に取り組んでいますが依然 Flutter の直接ネイティブ実行に分があります）。また、開発には Node.js 環境や Gradle 設定など多くのツールチェーンを統合する必要があり、セットアップやビルドがやや複雑です。総じて<strong>技術面では、パフォーマンスと一貫性で Flutter が優れ、Web 技術資産の再利用性で React Native が優れる</strong>と言えます。</p>
<p><h3><span id="toc7">開発者の支持率</span></h3>
</p>
<p><strong>開発者コミュニティの支持</strong>: 開発者からの人気・支持という面でも両者に差が出つつあります。Stack Overflow の開発者調査「最も愛されるフレームワーク」部門では、Flutter は<strong>68%前後の開発者から「好き」と評価</strong>されており、React Native の約 55 ～ 58%を上回っています (<a href="https://gist.github.com/tkrotoff/93f5278a4e8df7e5f6928eff98684979#:~:text=%2A%20Popularity%3A%20Flutter%2012.64,React%20Native%2013.05">React Native vs Flutter · GitHub</a>)。これは Flutter 開発者の多くがその経験に満足していることを示します。一方、React Native は Flutter に比べやや満足度で劣り、「どちらかといえば敬遠される」層も一定数います。ただし<strong>JavaScript/React 経験者の圧倒的な母数</strong>があるため、依然として学習コストの低さから React Native を選ぶ開発者も少なくありません。GitHub のコントリビューションを見ると、Flutter リポジトリのコミット数が RN より多く活発に開発が進められている一方で、RN は未マージのプルリクエスト件数が Flutter より多く、オープンソース貢献の受け皿としても機能しています (<a href="https://flatirons.com/blog/popularity-of-flutter-vs-react-native-2024/#:~:text=GitHub%20Commits">Popularity of Flutter vs. React Native in 2025 &#8211; Flatirons</a>)。今後も<strong>Flutter は Google 主導の安定したアップデート</strong>が続く見込みで、開発者コミュニティの勢いは Flutter が優位でしょう。</p>
<p><h3><span id="toc8">パフォーマンス比較</span></h3>
</p>
<p><strong>速度・効率</strong>: パフォーマンス面では、総合すると Flutter が有利と考えられます。Flutter はネイティブコードに直接コンパイルされるため、スクロールやアニメーションの滑らかさ、描画フレームレートで高い水準を示します (<a href="https://springsapps.com/knowledge/flutter-vs-react-native-in-2024#:~:text=In%20terms%20of%20performance%2C%20Flutter,its%20performance%20compared%20to%20Flutter">Flutter vs React Native in 2025 &#8211; Springs</a>)。事例でも、Flutter 製アプリがしばしば「ネイティブと遜色ない」「カクつきが減った」と評価されます。React Native も日常的な CRUD アプリ程度であれば実用十分な速度がありますが、JS とネイティブ間通信がボトルネックになる処理（大量の一覧描画や同期的な複雑演算など）では Flutter との差が現れます。もっとも、React Native 側も近年「Fabric」という新レンダリングエンジンや Turbo Modules により、ブリッジのオーバーヘッド削減を進めています。軽量な UI や一部ネイティブモジュールの組み合わせ次第では RN でもほぼネイティブ並みの体感速度を実現できます。<strong>一般論としては UI 表現力とピーク性能で Flutter が上回り、RN は十分実用的だが極限では Flutter に一歩譲る</strong>という状況です (<a href="https://springsapps.com/knowledge/flutter-vs-react-native-in-2024#:~:text=In%20terms%20of%20performance%2C%20Flutter,its%20performance%20compared%20to%20Flutter">Flutter vs React Native in 2025 &#8211; Springs</a>)。</p>
<p><h3><span id="toc9">将来の成長予測</span></h3>
</p>
<p>以上を踏まえ、<strong>今後より成長する可能性が高いのは Flutter</strong>だと予測します。理由は以下の通りです。</p>
<li><strong>採用企業の増加</strong>: 新興企業や既存プロダクトの刷新で Flutter を採用する動きが加速しています。Google 自身が Flutter を重要プロジェクトに適用し続けていることも信頼感に繋がり、Flutter 選択の企業が今後も増えるでしょう。一方、React Native は現状維持的な採用が多く、新たな大規模事例は以前ほど聞かれなくなっています。</li>
<li><strong>コミュニティと市場シェア</strong>: 開発者コミュニティの勢い・シェアともに Flutter がリードしており (<a href="https://code-b.dev/blog/flutter-vs-react-native#:~:text=Flutter%20%26%20React%20Native%20Compared,Flutter%20for%20their%20app">Flutter &#038; React Native Compared | Best Framework for your Project?</a>) (<a href="https://gist.github.com/tkrotoff/93f5278a4e8df7e5f6928eff98684979#:~:text=2023%20,2023%2Fdevelopment%2F%23mobile">React Native vs Flutter · GitHub</a>)、このトレンドは当面続く見込みです。特に新世代のモバイル開発者に Flutter が支持されていることは将来の人材供給面でも強みです。</li>
<li><strong>技術革新のスピード</strong>: Flutter は年次の大型アップデート（Flutter 3 以降も継続的に改良）が活発で、Web やデスクトップ、組み込み領域への展開など着実にプラットフォームを拡大しています。React Native もアップデートは続いていますが、元々の設計上 Web 対応は別プロジェクト（React Native Web）に頼る必要があるなど、守備範囲が限定的です。マルチプラットフォーム対応力で Flutter が先行しています。</li>
<li><strong>パフォーマンスと体験</strong>: ユーザー体験の質に直結するパフォーマンスで優位なこと、UI デザインの自由度が高いことから、企業が「よりリッチで高速なアプリ」を目指す場合 Flutter を選ぶ傾向が強まるでしょう。実際 Tencent や BMW が Flutter を選択したのはパフォーマンスと開発効率の両立が理由です (<a href="https://www.goodfirms.co/blog/flutter-2025-definition-key-trends-statistics#:~:text=,10%20million%20daily%20active%20users">Flutter 2025: Definition, Key Trends, and Statistics</a>) (<a href="https://www.nomtek.com/blog/flutter-app-examples#:~:text=Thanks%20to%20Flutter%2C%20BMW%20deployed,resolved%20after%20migrating%20to%20Flutter">Companies Using Flutter in 2024</a>)。</li>
<p>総合すると、React Native も依然有力なクロスプラットフォーム手段ではありますが、<strong>今後数年の成長率や新規プロジェクト採用においては Flutter が React Native を上回る</strong>可能性が高いです (<a href="https://code-b.dev/blog/flutter-vs-react-native#:~:text=Flutter%20%26%20React%20Native%20Compared,Flutter%20for%20their%20app">Flutter &#038; React Native Compared | Best Framework for your Project?</a>)。もっとも各技術には得意分野があるため、Web 資産を流用したいケースでは引き続き React Native が選ばれるなど、両者が共存しつつも Flutter が主導権を握る形で市場が推移していくと考えられます。</p>
<p><strong>参考資料</strong>:</p>
<li>Flutter 国内導入事例: ユニクロ、スシロー、じゃらんなど (<a href="https://pentagon.tokyo/app/6357/#:~:text=Flutter%E8%A3%BD%E3%81%AE%E6%9C%89%E5%90%8D%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AF%E3%80%81%E3%83%A6%E3%83%8B%E3%82%AF%E3%83%AD%E3%80%81%E6%9D%BE%E5%B1%8B%E3%80%81%E3%82%B9%E3%82%B7%E3%83%AD%E3%83%BC%E3%80%81%E3%81%98%E3%82%83%E3%82%89%E3%82%93%E3%80%81%E3%81%AA%E3%81%A9%E3%81%8C%E3%81%82%E3%81%92%E3%82%89%E3%82%8C%E3%81%BE%E3%81%99%E3%80%82">Flutter アプリの国内事例 12 選！大手の Flutter 移行も紹介 | 東京のアプリ開発会社</a>)</li>
<li>Flutter 海外導入事例: Google Pay、Alibaba（Xianyu）、Nubank、BMW 他 (<a href="https://www.goodfirms.co/blog/flutter-2025-definition-key-trends-statistics#:~:text=,10%20million%20daily%20active%20users">Flutter 2025: Definition, Key Trends, and Statistics</a>)</li>
<li>Flutter vs React Native の統計比較: 開発者利用率・人気度 (<a href="https://gist.github.com/tkrotoff/93f5278a4e8df7e5f6928eff98684979#:~:text=%2A%20Popularity%3A%20Flutter%2012.64,React%20Native%2013.05">React Native vs Flutter · GitHub</a>)</li>
<li>技術的比較と性能評価: Flutter のネイティブ高速性、RN の JS ブリッジによる差(<a href="https://springsapps.com/knowledge/flutter-vs-react-native-in-2024#:~:text=In%20terms%20of%20performance%2C%20Flutter,its%20performance%20compared%20to%20Flutter">Flutter vs React Native in 2025 &#8211; Springs</a>)</li><p>The post <a href="https://aichi.blog/flutter-app-examples/">Flutter 製アプリの事例と Flutter vs React Native の将来展望</a> first appeared on <a href="https://aichi.blog">AichiLog</a>.</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>enviedパッケージを使用して、環境変数をより安全に管理する</title>
		<link>https://aichi.blog/flutter-env-file-2/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=flutter-env-file-2</link>
		
		<dc:creator><![CDATA[愛知郎]]></dc:creator>
		<pubDate>Thu, 13 Feb 2025 14:51:51 +0000</pubDate>
				<category><![CDATA[Flutter]]></category>
		<category><![CDATA[チーム開発]]></category>
		<category><![CDATA[デプロイ]]></category>
		<category><![CDATA[開発]]></category>
		<guid isPermaLink="false">https://aichi.blog/flutter-env-file-2/</guid>

					<description><![CDATA[<p>目次 はじめに1. enviedのインストール2. .envファイルの作成3. 環境変数を管理するファイルを作成4. env.g.dartの生成生成されるenv.g.dart5. 環境変数の使用方法6. enviedが環 [&#8230;]</p>
<p>The post <a href="https://aichi.blog/flutter-env-file-2/">enviedパッケージを使用して、環境変数をより安全に管理する</a> first appeared on <a href="https://aichi.blog">AichiLog</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>
  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-14" checked><label class="toc-title" for="toc-checkbox-14">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">はじめに</a></li><li><a href="#toc2" tabindex="0">1. enviedのインストール</a></li><li><a href="#toc3" tabindex="0">2. .envファイルの作成</a></li><li><a href="#toc4" tabindex="0">3. 環境変数を管理するファイルを作成</a></li><li><a href="#toc5" tabindex="0">4. env.g.dartの生成</a><ol><li><a href="#toc6" tabindex="0">生成されるenv.g.dart</a></li></ol></li><li><a href="#toc7" tabindex="0">5. 環境変数の使用方法</a></li><li><a href="#toc8" tabindex="0">6. enviedが環境変数を管理する上で安全な理由</a></li><li><a href="#toc9" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p>Flutterアプリ開発において、APIキーやデータベースパスワードなどの機密情報を安全に管理することは非常に重要です。本記事では、<code>envied</code>パッケージを使用して環境変数を安全に管理する方法を解説します。</p>
<p><h2><span id="toc2">1. enviedのインストール</span></h2>
<p>まず、Flutterプロジェクトに<code>envied</code>パッケージを追加します。</p>
<pre><code class="language-bash">flutter pub add envied
flutter pub add --dev build_runner envied_generator</code></pre>
<p><code>envied</code>は環境変数を安全に管理するためのパッケージで、<code>build_runner</code>と<code>envied_generator</code>を利用してコードを自動生成します。</p>
<p><h2><span id="toc3">2. .envファイルの作成</span></h2>
<p>環境変数を定義するために、<code>.env</code>ファイルをプロジェクトのルートディレクトリに作成し、以下のように記述します。</p>
<pre><code class="language-bash">DB_PASSWORD=1234567890
DB_PORT=3000</code></pre>
<p>このファイルには機密情報を含むため、<code>.gitignore</code>に追加してバージョン管理から除外してください。</p>
<pre><code class="language-bash">echo ".env" >> .gitignore
echo "env.g.dart" >> .gitignore  # のちに生成されるファイル</code></pre>
<p><h2><span id="toc4">3. 環境変数を管理するファイルを作成</span></h2>
<p>次に、<code>lib/env.dart</code>というファイルを作成し、以下のコードを記述します。</p>
<pre><code class="language-dart">import 'package:envied/envied.dart';
part 'env.g.dart';
<p>// requireEnvFileがtrueの場合、.envファイルがないとエラーが出る
@Envied(requireEnvFile: true, path: '.env')
final class Env {
  @EnviedField(varName: 'DB_PASSWORD')
  static const String dbPassword = _Env.dbPassword;</p>
  @EnviedField(varName: 'DB_PORT')
  static const String dbPort = _Env.dbPort;
}</code></pre>
<p>このファイルでは、<code>@Envied</code>アノテーションを使用して<code>.env</code>ファイルから環境変数を読み込むように設定します。</p>
<p><h2><span id="toc5">4. env.g.dartの生成</span></h2>
<p>環境変数を自動生成するために、以下のコマンドを実行します。</p>
<pre><code class="language-bash">flutter pub run build_runner build --delete-conflicting-outputs</code></pre>
<p>このコマンドを実行すると、<code>env.g.dart</code>というファイルが自動生成されます。</p>
<p><h3><span id="toc6">生成されるenv.g.dart</span></h3>
</p>
<pre><code class="language-dart">// GENERATED CODE - DO NOT MODIFY BY HAND
<p>part of 'env.dart';</p>
<p>// ************************************************************************<strong>
// EnviedGenerator
// </strong>**********************************************************************<strong></p>
// coverage:ignore-file
// ignore_for_file: type=lint
// generated_from: .env
final class _Env {
  static const String dbPassword = '1234567890'; // envの中身がここにくる
  static const String dbPort = '3000';
}</code></pre>
<p>このファイルが生成されたら、<code>.env</code>ファイルは削除しても問題ありません。</p>
<pre><code class="language-bash">rm .env</code></pre>
<p><h2><span id="toc7">5. 環境変数の使用方法</span></h2>
<p>アプリケーション内で環境変数を使用する際は、以下のように呼び出します。</p>
<pre><code class="language-dart">import 'env.dart';
void main() {
  print(Env.dbPassword);
  print(Env.dbPort);
}</code></pre>
<p>このコードを実行すると、<code>.env</code>ファイルに定義した値が出力されます。</p>
<p><h2><span id="toc8">6. enviedが環境変数を管理する上で安全な理由</span></h2>
</p>
<p>なぜ、このような手間をかけて、環境変数を管理する必要があるのでしょうか？<br />
それは、enviedが環境変数を暗号化してくれるからです。</p>
<p>通常この暗号化は、アプリのビルド時に行われます。<br />
ただ、開発の段階で、環境変数を暗号化する機能もあります。</p>
<pre><code class="language-dart">import 'package:envied/envied.dart';
part 'env.g.dart';
@Envied(requireEnvFile: true, path: '.env')
final class Env {
  // 暗号化する場合は、obfuscate: trueを追加
  @EnviedField(varName: 'DB_PASSWORD', obfuscate: true)
  static String dbPassword = _Env.dbPassword;
  @EnviedField(varName: 'DB_PORT')
  static String dbPort = _Env.dbPort;
}</code></pre>
<p>暗号化された場合（今回だと<code>dbPassword</code>）、生成される<code>env.g.dart</code>は以下のようになります。</p>
<pre><code class="language-dart">// GENERATED CODE - DO NOT MODIFY BY HAND
<p>part of 'env.dart';</p>
<p>// </strong>**********************************************************************<strong>
// EnviedGenerator
// </strong>************************************************************************</p>
<p>// coverage:ignore-file
// ignore_for_file: type=lint
// generated_from: .env
final class _Env {
  static const List<int> _enviedkeydbPassword = <int>[
    3175743209,
    3642003943,
    2774983698,
    2234134847,
    776266119,
    3460629094,
    2118227522,
    209157887,
    2325619839,
    559751284,
  ];</p>
<p>static const List<int> _envieddatadbPassword = <int>[
    3175743192,
    3642003925,
    2774983713,
    2234134795,
    776266162,
    3460629072,
    2118227573,
    209157831,
    2325619782,
    559751236,
  ];</p>
<p>static final String dbPassword = String.fromCharCodes(List<int>.generate(
    _envieddatadbPassword.length,
    (int i) => i,
    growable: false,
  ).map((int i) => _envieddatadbPassword[i] ^ _enviedkeydbPassword[i]));</p>
  static const String dbPort = '3000';
}</code></pre>
<p><h2><span id="toc9">まとめ</span></h2>
<ul>
<li><code>envied</code>を利用することで、安全に環境変数を管理できる。</li>
<li><code>.env</code>ファイルはバージョン管理から除外する。</li>
<li><code>env.g.dart</code>も<code>.gitignore</code>に追加する。</li>
<li><code>build_runner</code>を使用して<code>env.g.dart</code>を自動生成する。</li>
<li>生成された<code>env.g.dart</code>を使用して環境変数を取得する。</li>
</ul>
<p>この方法を活用することで、Flutterアプリのセキュリティを向上させることができます。ぜひ、試してみてください！</p><p>The post <a href="https://aichi.blog/flutter-env-file-2/">enviedパッケージを使用して、環境変数をより安全に管理する</a> first appeared on <a href="https://aichi.blog">AichiLog</a>.</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>【Flutter】dotenv パッケージを使って環境変数を安全に管理する方法</title>
		<link>https://aichi.blog/flutter-env-file/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=flutter-env-file</link>
		
		<dc:creator><![CDATA[愛知郎]]></dc:creator>
		<pubDate>Wed, 12 Feb 2025 14:53:26 +0000</pubDate>
				<category><![CDATA[Flutter]]></category>
		<category><![CDATA[開発]]></category>
		<guid isPermaLink="false">https://aichi.blog/flutter-env-file/</guid>

					<description><![CDATA[<p>本記事では、`flutter_dotenv` パッケージを活用して環境変数を設定する方法を解説します。 目次 環境変数の設定手順1. flutter_dotenv パッケージのインストール2. .env ファイルの作成3 [&#8230;]</p>
<p>The post <a href="https://aichi.blog/flutter-env-file/">【Flutter】dotenv パッケージを使って環境変数を安全に管理する方法</a> first appeared on <a href="https://aichi.blog">AichiLog</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>本記事では、`flutter_dotenv` パッケージを活用して環境変数を設定する方法を解説します。</p>

  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-16" checked><label class="toc-title" for="toc-checkbox-16">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">環境変数の設定手順</a><ol><li><a href="#toc2" tabindex="0">1. flutter_dotenv パッケージのインストール</a></li><li><a href="#toc3" tabindex="0">2. .env ファイルの作成</a></li><li><a href="#toc4" tabindex="0">3. アセットの設定</a></li><li><a href="#toc5" tabindex="0">4. 環境変数の読み込み</a></li><li><a href="#toc6" tabindex="0">5. 環境変数の利用</a></li></ol></li><li><a href="#toc7" tabindex="0">環境変数管理</a><ol><li><a href="#toc8" tabindex="0">.gitignore に .env を追加する</a></li><li><a href="#toc9" tabindex="0">環境ごとに .env ファイルを分ける</a></li></ol></li><li><a href="#toc10" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">環境変数の設定手順</span></h2>
<h3><span id="toc2">1. flutter_dotenv パッケージのインストール</span></h3>
<p>まず、`flutter_dotenv` パッケージをプロジェクトに追加します。以下のコマンドを実行してください：</p>
<pre><code>
flutter pub add flutter_dotenv
</code></pre>
<h3><span id="toc3">2. .env ファイルの作成</span></h3>
<p>プロジェクトのルートディレクトリに `.env` ファイルを作成し、環境変数を定義します。</p>
<pre><code>
API_KEY=your_api_key_here
</code></pre>
<h3><span id="toc4">3. アセットの設定</span></h3>
<p>作成した `.env` ファイルを Flutter に認識させるために、`pubspec.yaml` に以下の設定を追加します：</p>
<pre><code>
flutter:
  assets:
    - .env
</code></pre>
<h3><span id="toc5">4. 環境変数の読み込み</span></h3>
<p>アプリケーションの起動時に環境変数を読み込むため、main.dart を修正します。</p>
<pre><code>import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter/material.dart';
import 'my_app.dart'; // 実際のアプリケーションファイルをインポート
void main() async {
 await dotenv.load(fileName: ".env"); // ここでenvファイルを読み込む
 runApp(const MyApp());
} </code></pre>
<h3><span id="toc6">5. 環境変数の利用</span></h3>
<p>環境変数の設定が完了したら、アプリケーション内で以下のように参照できます：</p>
<pre><code>
final apiKey = dotenv.env['API_KEY'];
print("API Key: $apiKey");
</code></pre>
<h2><span id="toc7">環境変数管理</span></h2>
<h3><span id="toc8">.gitignore に .env を追加する</span></h3>
<p>`.env` ファイルには機密情報が含まれるため、バージョン管理システム（Git など）に追加されないように `.gitignore` に以下の設定を記述してください：</p>
<pre><code>
.env
</code></pre>
<h3><span id="toc9">環境ごとに .env ファイルを分ける</span></h3>
<p>開発・ステージング・本番環境で異なる環境変数を使用する場合、.env.dev、.env.prod など複数のファイルを用意し、dotenv.load(fileName: &#8220;env_file_name&#8221;) で適切なファイルを読み込むようにしましょう。</p>
<pre><code>
void main() async {
  await dotenv.load(fileName: ".env.prod");
  runApp(const MyApp());
}
</code></pre>
<h2><span id="toc10">まとめ</span></h2>
<p>Flutter アプリケーションで環境変数を安全に管理するための手順を解説しました。`flutter_dotenv` を活用すれば、API キーや認証情報を安全に管理できるため、セキュリティリスクを減らすことができます。</p>
<p><strong>ポイントまとめ</strong><br />
&#8211; flutter_dotenv を使用して環境変数を管理<br />
&#8211; .env ファイルを .gitignore に追加<br />
&#8211; 環境ごとに異なる .env ファイルを活用</p>
<p>Flutter アプリ開発において、適切な環境変数管理を実践し、安全なアプリケーション運用を目指しましょう！</p><p>The post <a href="https://aichi.blog/flutter-env-file/">【Flutter】dotenv パッケージを使って環境変数を安全に管理する方法</a> first appeared on <a href="https://aichi.blog">AichiLog</a>.</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Go言語におけるディレクトリ構成のベストプラクティス</title>
		<link>https://aichi.blog/go-directory-structure/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=go-directory-structure</link>
		
		<dc:creator><![CDATA[愛知郎]]></dc:creator>
		<pubDate>Tue, 11 Feb 2025 14:56:18 +0000</pubDate>
				<category><![CDATA[Go]]></category>
		<category><![CDATA[開発]]></category>
		<guid isPermaLink="false">https://aichi.blog/go-directory-structure/</guid>

					<description><![CDATA[<p>本記事では、標準的なGoプロジェクトの構成と、それに基づいたベストプラクティスについて解説します。 目次 1. 標準的なプロジェクト構成2. 重要なディレクトリの説明cmd/internal/pkg/api/web/co [&#8230;]</p>
<p>The post <a href="https://aichi.blog/go-directory-structure/">Go言語におけるディレクトリ構成のベストプラクティス</a> first appeared on <a href="https://aichi.blog">AichiLog</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>本記事では、標準的なGoプロジェクトの構成と、それに基づいたベストプラクティスについて解説します。</p>

  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-18" checked><label class="toc-title" for="toc-checkbox-18">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">1. 標準的なプロジェクト構成</a></li><li><a href="#toc2" tabindex="0">2. 重要なディレクトリの説明</a><ol><li><a href="#toc3" tabindex="0">cmd/</a></li><li><a href="#toc4" tabindex="0">internal/</a></li><li><a href="#toc5" tabindex="0">pkg/</a></li><li><a href="#toc6" tabindex="0">api/</a></li><li><a href="#toc7" tabindex="0">web/</a></li><li><a href="#toc8" tabindex="0">configs/</a></li><li><a href="#toc9" tabindex="0">scripts/</a></li><li><a href="#toc10" tabindex="0">test/</a></li><li><a href="#toc11" tabindex="0">docs/</a></li></ol></li><li><a href="#toc12" tabindex="0">3. ベストプラクティス</a><ol><li><a href="#toc13" tabindex="0">パッケージ構造</a></li><li><a href="#toc14" tabindex="0">依存関係</a></li><li><a href="#toc15" tabindex="0">可視性</a></li><li><a href="#toc16" tabindex="0">テスト</a></li></ol></li><li><a href="#toc17" tabindex="0">4. 参考文献</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">1. 標準的なプロジェクト構成</span></h2>
<p>Goプロジェクトでは、以下のようなディレクトリ構成を採用するのが一般的です。</p>
<pre><code>
project-root/
├── cmd/           # メインアプリケーションのエントリーポイント
│   └── app/
│       └── main.go
├── internal/      # 非公開のパッケージ
│   ├── auth/
│   ├── db/
│   └── handler/
├── pkg/           # 公開パッケージ
│   ├── models/
│   └── utils/
├── api/           # API定義、プロトコルファイルなど
├── web/           # Webアプリケーションの静的ファイル
├── configs/       # 設定ファイル
├── scripts/       # ビルドスクリプトなど
├── test/          # 追加のテストファイル
├── docs/          # ドキュメント
├── go.mod
└── go.sum
</code></pre>
<p>この構成を採用することで、コードの役割が明確になり、プロジェクトのスケールアップにも対応しやすくなります。</p>
<h2><span id="toc2">2. 重要なディレクトリの説明</span></h2>
<h3><span id="toc3">cmd/</span></h3>
<p>&#8211; アプリケーションのメインエントリーポイントを格納します。<br />
&#8211; 各実行可能ファイルは独自のディレクトリを持つべきです。</p>
<h3><span id="toc4">internal/</span></h3>
<p>&#8211; プロジェクト内部でのみ使用するプライベートなコードを配置します。<br />
&#8211; Goコンパイラによって外部からのインポートが禁止されるため、実装の隠蔽に役立ちます。</p>
<h3><span id="toc5">pkg/</span></h3>
<p>&#8211; 他のプロジェクトでも再利用可能な公開パッケージを配置します。<br />
&#8211; 安定したAPIを提供し、慎重に設計する必要があります。</p>
<h3><span id="toc6">api/</span></h3>
<p>&#8211; OpenAPI仕様やgRPCプロトコル定義ファイルを格納します。</p>
<h3><span id="toc7">web/</span></h3>
<p>&#8211; フロントエンドの静的ファイル（HTML、CSS、JavaScriptなど）を配置します。</p>
<h3><span id="toc8">configs/</span></h3>
<p>&#8211; 設定ファイル（YAML、JSON、TOMLなど）を格納します。</p>
<h3><span id="toc9">scripts/</span></h3>
<p>&#8211; デプロイやビルドに使用するスクリプトを配置します。</p>
<h3><span id="toc10">test/</span></h3>
<p>&#8211; ユニットテストとは別に、統合テストやエンドツーエンドテストのスクリプトを配置します。</p>
<h3><span id="toc11">docs/</span></h3>
<p>&#8211; プロジェクトのドキュメントを格納します。</p>
<h2><span id="toc12">3. ベストプラクティス</span></h2>
<h3><span id="toc13">パッケージ構造</span></h3>
<p>&#8211; 各ディレクトリは単一の責任を持つように設計します。<br />
&#8211; パッケージ名は簡潔で意味のあるものにします。</p>
<h3><span id="toc14">依存関係</span></h3>
<p>&#8211; 循環依存を避けるため、適切にモジュールを分離します。<br />
&#8211; 依存関係は上位レベルから下位レベルへ向かうべきです。</p>
<h3><span id="toc15">可視性</span></h3>
<p>&#8211; 内部実装は `internal/` パッケージに配置し、外部公開を防ぎます。<br />
&#8211; 再利用可能なコードは `pkg/` ディレクトリに配置します。</p>
<h3><span id="toc16">テスト</span></h3>
<p>&#8211; テストファイルは実装ファイルと同じディレクトリに配置し、 `*_test.go` という命名規則を守ります。<br />
&#8211; 統合テストやエンドツーエンドテストは `test/` ディレクトリに配置します。</p>
<p>このような構成を採用することで、コードの保守性が向上し、チーム開発がスムーズに進行します。</p>
<h2><span id="toc17">4. 参考文献</span></h2>
<p>1. <a href="https://go.dev/blog/">Go公式ブログ</a><br />
2. <a href="https://github.com/golang/go">Go標準ライブラリのソースコード</a><br />
3. <a href="https://github.com/golang-standards/project-layout">Goプロジェクトレイアウト（非公式）</a></p>
<p>Goプロジェクトにおける設計の助けになれば幸いです。</p><p>The post <a href="https://aichi.blog/go-directory-structure/">Go言語におけるディレクトリ構成のベストプラクティス</a> first appeared on <a href="https://aichi.blog">AichiLog</a>.</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>WordPress API のレスポンスでなぜか HTML が返される（トップページにリダイレクトされる）</title>
		<link>https://aichi.blog/wordpress-api-html-response/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=wordpress-api-html-response</link>
		
		<dc:creator><![CDATA[愛知郎]]></dc:creator>
		<pubDate>Mon, 10 Feb 2025 14:51:16 +0000</pubDate>
				<category><![CDATA[Wordpress]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[開発]]></category>
		<guid isPermaLink="false">https://aichi.blog/wordpress-api-html-response/</guid>

					<description><![CDATA[<p>WordPress REST API でHTMLが返ってしまう原因と対処法 目次 はじめに発生した問題実行したAPIリクエスト試した対処法1. REST APIが無効化されていないか確認2. プラグインの影響を確認原因： [&#8230;]</p>
<p>The post <a href="https://aichi.blog/wordpress-api-html-response/">WordPress API のレスポンスでなぜか HTML が返される（トップページにリダイレクトされる）</a> first appeared on <a href="https://aichi.blog">AichiLog</a>.</p>]]></description>
										<content:encoded><![CDATA[<h1>WordPress REST API でHTMLが返ってしまう原因と対処法</h1>

  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-20" checked><label class="toc-title" for="toc-checkbox-20">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"></li><li><a href="#toc1" tabindex="0">はじめに</a></li><li><a href="#toc2" tabindex="0">発生した問題</a><ol><li><a href="#toc3" tabindex="0">実行したAPIリクエスト</a></li></ol></li><li><a href="#toc4" tabindex="0">試した対処法</a><ol><li><a href="#toc5" tabindex="0">1. REST APIが無効化されていないか確認</a></li><li><a href="#toc6" tabindex="0">2. プラグインの影響を確認</a></li></ol></li><li><a href="#toc7" tabindex="0">原因：パーマリンク設定</a><ol><li><a href="#toc8" tabindex="0">解決策</a></li></ol></li><li><a href="#toc9" tabindex="0">まとめ</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">はじめに</span></h2>
<p>WordPress（以下、WP）でREST APIを使用する際に、通常JSONデータが返されるはずのエンドポイントから、なぜかHTMLが返ってしまうという問題に遭遇しました。</p>
<p>認証周りの設定ミスを疑いましたが、GETメソッドでAPIを叩いた場合でも同様にHTMLが返ってくる状況でした。</p>
<p>本記事では、この問題の原因と具体的な対処法について解説します。</p>
<h2><span id="toc2">発生した問題</span></h2>
<p>WordPressのREST APIを使用して記事データを取得しようとした際に、意図したJSONデータではなくHTMLが返される現象が発生しました。</p>
<h3><span id="toc3">実行したAPIリクエスト</span></h3>
<pre><code>bash
curl -X GET http://example.com/wp-json/wp/v2/posts
</code></pre>
<p>通常、このAPIエンドポイントをGETメソッドで叩いた場合、認証なしでもJSONデータが返されるはずです。しかし、実際にはHTMLが返ってきてしまいました。</p>
<p>参考: <a href="https://ja.wp-api.org/reference/posts/">WordPress REST API ドキュメント</a></p>
<h2><span id="toc4">試した対処法</span></h2>
<h3><span id="toc5">1. REST APIが無効化されていないか確認</span></h3>
<p>最初に疑ったのは、REST APIが何らかの理由で無効化されている可能性です。以下の点を確認しました。</p>
<p>&#8211; `functions.php` に `rest_api_init` を無効化するコードがないか<br />
&#8211; `.htaccess` や `wp-config.php` にREST APIをブロックする設定がないか</p>
<p>しかし、特に問題は見つかりませんでした。</p>
<h3><span id="toc6">2. プラグインの影響を確認</span></h3>
<p>次に、インストール済みのプラグインがREST APIの動作を妨げている可能性を疑いました。</p>
<p>&#8211; すべてのプラグインを一時的に無効化<br />
&#8211; ひとつずつ有効化して再テスト</p>
<p>しかし、プラグインにも問題はありませんでした。</p>
<h2><span id="toc7">原因：パーマリンク設定</span></h2>
<p>問題の原因は <strong>パーマリンク設定</strong> にありました。</p>
<p><img decoding="async" src="https://aichi.blog/wp-content/uploads/2025/02/wp_permalink-1.jpg" alt="パーマリンク設定画像" /></p>
<p>WordPressでは、REST APIを利用する際にパーマリンク設定が影響を及ぼすことがあります。特に、パーマリンク設定が「基本」や「日付」などの <strong>数字ベース</strong> の形式になっていると、REST APIのエンドポイントが適切に認識されず、HTMLが返されてしまうことがあります。</p>
<h3><span id="toc8">解決策</span></h3>
<p>パーマリンク設定を <strong>「投稿名」</strong> に変更することで、問題は解決しました。</p>
<h4>設定手順</h4>
<p>1. WordPress管理画面にログイン<br />
2. <strong>設定</strong> → <strong>パーマリンク</strong> を開く<br />
3. <strong>「投稿名」</strong> を選択<br />
4. <strong>変更を保存</strong> をクリック</p>
<p>この変更を行った後に、再度APIを叩いたところ、期待通りのJSONデータが返ってくるようになりました。</p>
<h2><span id="toc9">まとめ</span></h2>
<p>WordPress REST API を利用する際に、意図しないHTMLが返ってくる場合は、パーマリンクの設定を確認してください。</p>
<p>この問題は意外と見落としがちですが、WP REST APIを正しく動作させるためには非常に重要です。</p>
<p>同じような問題で困っている方は、ぜひこの方法を試してみてください！</p><p>The post <a href="https://aichi.blog/wordpress-api-html-response/">WordPress API のレスポンスでなぜか HTML が返される（トップページにリダイレクトされる）</a> first appeared on <a href="https://aichi.blog">AichiLog</a>.</p>]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
