コロナ禍に弥生へ中途入社したエンジニアの物語

初めまして、今年の5月に中途入社しました情報システム部エンジニアの飯田です! この記事は弥生 Advent Calendar 2020の2日目の記事です。

2日目(このブログでは初回)なので私も最近のマイブームの技術ネタを…といきたいところですが、せっかくなので私にしか書けないこととして、コロナ禍に弥生へ入社してから今までのことについて書いていきたいと思います!

簡単な経歴

中小のITベンチャーで新卒から10年半ほど勤務し、JavaやAWSを使ったシステム開発や、DevOps活動としてCI/CDパイプラインの構築などを行っていました。

仕事内容は良かったのですが、もうちょっと腰を据えて1つのプロダクトに関わりたいと思ったのと、まあ他にも色々あって転職を決意。ただ、何はともあれ10年間頑張ったということでリフレッシュするため、あえて転職先は決めずに退職しました。

3か月ほど旅行したり資格を取ったりした後に転職活動を始め、エージェントからの紹介で弥生を知りました。選考が進むにつれて、自分が働いていた(そして色んな苦労もあった)中小企業などの支えとなる「事業コンシェルジュ」という弥生のビジョンに惹かれていき、結果無事に内定を頂けて入社を決意しました。

リモートワークから始まった弥生人生

こうして5月1日から弥生の一員となったのですが、依然として緊急事態宣言中だったため初日からリモートワークでした。さらに私の場合は採用面接からオファー面談、入社前オリエンまで全てリモートで行なっていたため、本社に行ったことがないどころか弥生の社員の誰とも会わないうちに仕事を始めることになったのです!まさかこのような形で弥生人生がスタートするとは思ってもいませんでした(笑)

そもそも仕事をすること自体が数か月ぶりというのもあって不安だらけの初日でしたが、Zoomでのコミュニケーションは転職活動時の面接ですっかり慣れていましたし、自宅の機材もある程度のものが揃っていたので、思っていたほどの苦労や不便はありませんでした。仕事が終わってZoom部屋から出た時には不安はすっかり消えていて、達成感があり今後もうまくやっていけそうな感じがしました。

入社後しばらくの間は導入教育を少しずつ受け、弥生の開発プロセスや製品などについて学びます。実はリフレッシュ期間中に偶然にも簿記を勉強していたので、会計ソフトを開発している弥生への入社は運命だったのかも知れませんね。もっとも、簿記の知識が活かせることに気付いたのは内定を承諾した後だったんですけどね。

その後もリモートワークが続きましたが、7月の頭に突然自宅でネットワークトラブルが発生し、急遽初出社を果たすことになりました。秋葉原に行くのは友達に連れられてメイド喫茶に行って以来約15年ぶりです。そして私のチームのPMであり開発本部のCTLである山川さんと初めてお会いして色々と話をすることができました。弥生の一員となったことを改めて実感した瞬間です。ちなみに(3Dの)山川さんを見た時の第一印象は「でかっ!」でした(笑) Zoom越しだと身長や体格が分からないんですよね。

チームメンバー全員との顔合わせも10月に実現し、今でもまだ計3回しか出社できていませんが、チームにはすっかり馴染めたのではないかと思います。残念ながら新型コロナの再流行によってまたしばらくの間リモートオンリーとなりそうですが、チームで協力して仕事を進めていきたいと思います。

情報システム部で開発しています

続いて仕事内容についてです。私が配属されたのは開発本部の情報システム部で、お客さまが弥生のサービスを契約する時に操作する画面や契約に関するバッチ処理などを行う課金管理システムを開発しているチームに入りました。前職ではこのような部分は単にツールを使って管理していましたが、弥生ほどのユーザー数で独自のプランやキャンペーンを運用するとなると専用のシステムが必要になるのですね。

弥生製品を開発しているわけではありませんが、やっていることは設計から実装、試験、リリース、そして保守・運用とシステム開発そのものと言えます。さらに、課金管理システムは弥生製品や他の社内システムとも連携しており、弥生のビジネスの基盤となる部分でもあるので、難しいことも多いですが独自の面白さがあると思います。

私も既にひと通りのプロセスを経験し、最近では要求や課題の検討・調査や若手メンバーのフォロー、実環境でのデータメンテナンス作業などを担当するようになってきました。「腰を据えて1つのプロダクトに関わりたい」という転職時の希望も実現しつつあり、対応の幅を広げて力を発揮していけたらと思います。

組織全体も少しずつ見えてきました

最後に組織について少々。前職と比べて従業員数が10倍以上である弥生という組織はまるで別世界…のはずなのですが、ほぼリモートワークということもあってまだまだ見えていない部分が多そうだというのが正直なところです。歓迎ランチや勉強会など、コロナ前は行われていたイベントが休止していたのも影響しているのかも知れません。

ただ、リモートワークが定着してきた最近では徐々に再開してきており、歓迎ランチ改めリモート交流会のおかげで他にどんなチームがあってどんな雰囲気なのかが体感できましたし、今年7月に弥生と合併した元Misocaのメンバーが主催しているリモートランチ会のおかげで他チームのメンバーと雑談する機会もできました。

10月にはオンラインでの社員総会も開催され、多くのお客さまを支える弥生のすごさを改めて感じると共に、弥生賞の発表で様々なチームやプロジェクトの取り組みを知ることができました。自分も中小企業ならではの組織活動を経験してきているので、弥生でもそういったところに食い込んでいきたいです。

また、開発本部全体の状況を共有する全体会は定期的に行われていますが、情報システム部のみの全体会も10月から始まり、部内のより細かい動きや目標などが見える・分かるようになってきました。そうそう、少し前にとある作業を自動化するツールを作ってチーム内で話したところ、思っていた以上に好評で情報システム部全体会で発表しようという流れになり、つい先日LTをしてきました!個人の取り組みにスポットを当ててもらえて嬉しかったですし、また何かしようという意欲にも繋がりますね。この時のLTの内容については、今後も取り組みを続けて来月以降に記事を書いていきたいと思いますのでお楽しみに!

これからも頑張っていきます!

以上、弥生に入社してからこれまでのことを書いてきました。入社から7か月が経ち新たな目標を立てたところなので、改めて気を引き締め、挑戦していきたいと思います。それではまたこのブログでお会いしましょう!

仮想通貨のやり取りを体感してみよう!

はじめに

みなさんこんにちは。弥生のe-Sportsプレイヤー(自称)の上島です。 この記事は、Misoca+弥生 Advent Calendar 2019の24日目の記事です。

ブロックチェーンのことについて書きたいと思います。

目的

仮想通貨のやり取りを体感することにより、

  • ブロックチェーンとは何だ!!
  • この先はどんなことが起こるのか!!

ということに興味を持つきっかけにしてもらえることです。 まず、触ってみて、その後にいろんな記事を見ると、より理解が進むんじゃないかと!(^-^) (実際の仮想通貨取引所で、取引するわけではなく、自身のパソコン上で実験するだけなのでご安心を(笑))

僕は、ブロックチェーンに詳しいわけでもなく、具体的なアイデアは、なーんにも持ってないですが、なんとなくブロックチェーンが世の中をより良くしてくれるんじゃないか!!と信じてるんです。(今のところ)

ブロックチェーンとは

Wikipediaをご確認ください(笑) ja.wikipedia.org

ただ、ブロックチェーンの詳細は読まなくても、ちんぷんかんぷんでも気にせず進めましょう!

僕が大好きなゲームのキャラである、ガイル少佐が戦う前にいつもカッコいいことを言います。

「御託はいい、はじめよう。」

では、はじめよう!(^-^)/

シナリオ

  1. ヤヨイさんとミソカさんの二人が登場します。 f:id:ym_AdventC:20191216181446p:plain

  2. ヤヨイさんが仮想通貨を稼ぎます。 f:id:ym_AdventC:20191216181508p:plain

  3. ヤヨイさんが稼いだ仮想通貨をミソカさんにプレゼントします。 f:id:ym_AdventC:20191216181405p:plain

用意するもの

  1. Ubuntuの環境
  2. 好奇心(←一番大事!)

ブロックチェーンの体感

環境構築

sudo add-apt-repository -y ppa:ethereum/ethereum

sudo apt-get update
sudo apt-get install ethereum

// ヘルプが表示できるか確認
geth -h
NAME:
   geth - the go-ethereum command line interface

   Copyright 2013-2019 The go-ethereum Authors

USAGE:
   geth [options] command [command options] [arguments...]

VERSION:
   1.9.9-stable-01744997
  • ちょっとしたファイルを作成(ex. /tmp/geth/genesis.json)
{
  "config": {
    "chainId": 15,
    "homesteadBlock": 0,
    "eip150Block": 0,
    "eip155Block": 0,
    "eip158Block": 0,
    "byzantiumBlock": 0,
    "constantinopleBlock": 0,
    "petersburgBlock": 0,
    "ethash": {}
  },
  "difficulty": "1",
  "gasLimit": "8000000",
  "alloc": {
  }
}
  • 初期化
geth --datadir /tmp/geth init /tmp/geth/genesis.json
  • 起動
geth --networkid "15" --nodiscover --maxpeers 0 --datadir "/tmp/geth" console 2>> /tmp/geth/geth_err.log

お!なんか、JavaScript consoleってのが出たぞ!

Welcome to the Geth JavaScript console!

instance: Geth/v1.9.9-stable-01744997/linux-amd64/go1.13.4
at block: 0 (Thu, 01 Jan 1970 09:00:00 DST)
 datadir: /tmp/geth
 modules: admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0

>

ここから先は、JavaScript consoleにて実施!

ヤヨイさんとミソカさんの登録

// アカウント確認(何も登録されていません。)
> eth.accounts
[]

// ヤヨイさん登録
> personal.newAccount("yayoi")
"0xa4fc61a4bab3043b232519719c612e43d872c8c7"

// ミソカさん登録
> personal.newAccount("misoca")
"0xc4bf2220126765f71c66d41d0279df8b24155d50"

// アカウント確認(二人分登録された!)
> eth.accounts
["0xa4fc61a4bab3043b232519719c612e43d872c8c7", "0xc4bf2220126765f71c66d41d0279df8b24155d50"]

(ほんとは、引数はパスワードらしい。)

仮想通貨を稼ぐ

// ヤヨイさんの残高確認(ゼロ!
> eth.getBalance(eth.accounts[0])
0

// ミソカさんの残高確認(ゼロ!
> eth.getBalance(eth.accounts[1])
0

// お金を稼ぐ人の確認(ヤヨイさん)
> eth.coinbase
"0xa4fc61a4bab3043b232519719c612e43d872c8c7"

// お金稼ぎ開始!(マイニング/採掘)
> miner.start(8)
null

// マイニングしてるかな?
> eth.mining
true

// マイニング進んでいるかな?(ゼロは進んでない
> eth.blockNumber
0

> eth.blockNumber
0

> eth.blockNumber
0

// お!マイニング進んだ!
> eth.blockNumber
54

// マイニングを止める
> miner.stop()
null

// 稼ぎの確認(えええ!!!とんでもない報酬が!!
> eth.getBalance(eth.coinbase)
54000000000000000000

// と思いきや単位がおかしいので整えると54etherでした。
// さっきの単位は、wei(1wei = 0.000000000000000001ether)
> web3.fromWei(eth.getBalance(eth.coinbase), "ether")
54

// ヤヨイさんの残高
> web3.fromWei(eth.getBalance(eth.accounts[0]), "ether")
54

// ミソカさんの残高
> web3.fromWei(eth.getBalance(eth.accounts[1]), "ether")
0

仮想通貨をプレゼント

// ヤヨイさんからミソカさんへ30ether送るよ。
// ヤヨイさんのアカウントのロック解除
> personal.unlockAccount(eth.accounts[0], "yayoi")
true

// 送金!
// トランザクションのIDが出た!
> eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(30, "ether")})
"0x1b3f9f42680298472615c06df0069040d4fce7f5a699e1384a4125c8beca8c5b"

// トランザクションどうなってるかな?
// blockNumber:null -> ペンディング状態(合意されていない)
> eth.getTransaction("0x1b3f9f42680298472615c06df0069040d4fce7f5a699e1384a4125c8beca8c5b")
{
  blockHash: null,
  blockNumber: null,
  from: "0xa4fc61a4bab3043b232519719c612e43d872c8c7",
  gas: 21000,
  gasPrice: 1000000000,
  hash: "0x1b3f9f42680298472615c06df0069040d4fce7f5a699e1384a4125c8beca8c5b",
  input: "0x",
  nonce: 0,
  r: "0x39849ddf941ca7a8692fbe12a9713c0c482644a783c9890d04bf92fae42962a9",
  s: "0x66cf377744bea5cec28b93af715f725d1f4ac9c0400c0ef0055072c633688736",
  to: "0xc4bf2220126765f71c66d41d0279df8b24155d50",
  transactionIndex: null,
  v: "0x41",
  value: 30000000000000000000
}

// ペンディングになっているトランザクション確認
> eth.pendingTransactions
[{
    blockHash: null,
    blockNumber: null,
    from: "0xa4fc61a4bab3043b232519719c612e43d872c8c7",
    gas: 21000,
    gasPrice: 1000000000,
    hash: "0x1b3f9f42680298472615c06df0069040d4fce7f5a699e1384a4125c8beca8c5b",
    input: "0x",
    nonce: 0,
    r: "0x39849ddf941ca7a8692fbe12a9713c0c482644a783c9890d04bf92fae42962a9",
    s: "0x66cf377744bea5cec28b93af715f725d1f4ac9c0400c0ef0055072c633688736",
    to: "0xc4bf2220126765f71c66d41d0279df8b24155d50",
    transactionIndex: null,
    v: "0x41",
    value: 30000000000000000000
}]

// 取引の正当性を合意するために、マイニングだー!
> miner.start(8)

// 合意された!(空っぽになったから)
> eth.pendingTransactions
[]

// ミソカさんの残高が増えた~!
> web3.fromWei(eth.getBalance(eth.accounts[1]), "ether")
30

// トランザクションを確認してみましょう。
// ブロックがつながった!(blockNumber:に値が!)
> eth.getTransaction("0x1b3f9f42680298472615c06df0069040d4fce7f5a699e1384a4125c8beca8c5b")
{
  blockHash: "0x485681549c3bfe644b8e89062f733f362884232a7299d3cb92be4056e735b091",
  blockNumber: 28,
  from: "0xa4fc61a4bab3043b232519719c612e43d872c8c7",
  gas: 21000,
  gasPrice: 1000000000,
  hash: "0x1b3f9f42680298472615c06df0069040d4fce7f5a699e1384a4125c8beca8c5b",
  input: "0x",
  nonce: 0,
  r: "0x39849ddf941ca7a8692fbe12a9713c0c482644a783c9890d04bf92fae42962a9",
  s: "0x66cf377744bea5cec28b93af715f725d1f4ac9c0400c0ef0055072c633688736",
  to: "0xc4bf2220126765f71c66d41d0279df8b24155d50",
  transactionIndex: 0,
  v: "0x41",
  value: 30000000000000000000
}

// 無事に取引がブロックのチェーンに追加されました!

f:id:ym_AdventC:20191218165936p:plain

以上のように、

発生した取引が、あるルールに則り合意され、合意された取引はブロックとしてチェーンのようにつながっていく。

そしてその取引の内容は確認できて、改ざんできない!と言われている。

まとめ

いかがでしたか? 動かすだけならすごく簡単でしたね!!(といいつつ、動作確認するのにちょっとハマってたのは内緒です(笑)) ただ、裏側で使われている技術やアイデアは、非常にすごそうです。

テクノロジーって本当に興味深いですね!

僕もこれを機にブロックチェーンの理解を深めたいと思います!

では、いよいよ、明日はラスト! @kokuyouwindさんの「勉強会をtsudaる技術」です!チームワークのチェーンを繋ぎます!

あとがき

今回は、ブロックチェーンのプラットフォームとして、イーサリアムを利用しました。 本当は、NEMで表現したいなーと思って調べてみたんですが、サンプルが見つけられず、断念しました(笑)

ブロックチェーンと一言でいっても、色々な思想をもつプラットフォームがあって興味深いです。 それぞれのプラットフォームの思想を最も反映していることの一つが「コンセンサスアルゴリズム」ではないでしょうか。 コンセンサスアルゴリズムとは、「この取引ってOKだよね!?」って合意形成方法のようです。 それぞれメリットデメリットがあるようですし、どれが一番優れている!とかはないのかもしれないですね。

我々が解決したい問題がブロックチェーンで解決できそうなのであれば、

  • 本当にブロックチェーンで解決できるのか
  • 解決できるならどのプラットフォームを使えば良いのか
  • プラットフォーム利用しながら、どのようなシステム構成にすればいいのか

みたいなことを議論していきたいなーなんて妄想しています(笑)(もちろん、議論だけじゃなく実装もね!

さてさて、長くなりましたが、ブロックチェーンに興味を持ってくれる人が増えたらうれしいです!

最後に、

量子コンピューターが来たらブロックチェーンどうなるんだろーーーー!!

おわり

Electronアプリの画面側をWebに配置する

こんにちは。弥生の内山です。
この記事はMisoca+弥生 Advent Calendar 2019 22日目の記事です。

はじめに

Electronでアプリを作っています。
弊社のイベントでも、なんどかそのお話をしています。
(本記事は、直近の12/19の回で発表した内容をベースに加筆したものになります)

Electronのアプリは、大きく分けて以下の2つのパートで構成されています。

  • Main側:Node.jsのプロセス。OSの機能を呼び出したり、Renderer側を起動したりできる
  • Renderer側:Chromiumによる画面描画のプロセス。要するにブラウザなので、HTML+JS+CSSを用いて画面を描画することができる

Renderer側は、ブラウザと同様に、HTMLファイル(とJS, CSSファイル)を読み込んで画面描画を開始するのですが、このHTMLは、アプリ内に同梱したものだけでなく、Webに配置したものを読み込むことが可能です。

WebにHTML, JS, CSSを配置すると何がうれしいかと言うと、アプリに何か修正を行いたい場合、Renderer側の修正だけであれば、修正したバージョンをユーザーにインストールしてもらうことなく、修正が全ユーザーに反映されるということです。
要するに、インストール型アプリでありながら、部分的にWebアプリのようなリリースの利点が得られるということです。

我々のアプリは、当初はRenderer側のファイルもローカルに保持する構成で開発していたのですが、途中から上記のようなメリットを得るために、Renderer側をWebに配置する構成への変更を行いました。
この変更が、思ったよりも大変だったため、具体的に何を考え、どのような変更を行ったのかをまとめたのが、本記事の内容となります。

やったこと

Same Origin Policyを回避する

Same Origin Policyは、ブラウザで読み込んだページが属するオリジンのみからしかリソース取得を行えない、という制約です。
詳細は、以下のサイトをご覧ください。

developer.mozilla.org

要するに、ブラウザ上からは、ドメインが違うサイトへのHTTPリクエストは発生させられない、ということです。

Renderer側のファイルをアプリ内に同梱していたときは、ブラウザ的にはファイルリソースへのアクセスなので、Same Origin Policyが発動することはありませんでした。
しかし、Webからファイルを読み込む場合は、この制約が発生してしまいます。

これにより何が困るかと言うと、Renderer側からWebAPI等へのアクセスができなくなるということです。
本アプリでは、認証などのためにWebAPIを叩く必要があったため、これは困ります。

そこで、本アプリでは、HTTPリクエストを発生させる元を全てMain側に移しました。
Main側では、ElectronのnetモジュールNode.jsのhttpモジュール、あるいはaxiosに代表されるようなHTTPクライアントライブラリを使うことができます。

Renderer側からは、ElectronのIPCを通じて、Main側のHTTP呼び出し機能にアクセスします。

例えば、Main側はIPCで"http"というメッセージを受けたら、HTTPリクエストを行うようにしておきます(httpRequestはHTTPリクエストを行う関数です)。

ipcMain.on("http", async (event, message) => {
  event.returnValue = await httpRequest(message);
});

そして、preloadスクリプトに上記のIPC呼び出しを行う関数を定義しておき、Renderer側ではこの関数を呼ぶことで、HTTPリクエストを行うようにします。

global.httpRequest = (message) =>
  ipcRenderer.sendSync("http", message);

この変更により、Same Origin Policyは回避できました。
これによる副次的な効果として、Webに公開しているコード内に、アクセス先のURLや、WebAPIに渡すトークン等のパラメータを埋め込む必要がなくなったので、セキュリティ的にもよかったと思います。

ローカルでの動作確認用にWebサーバーを立てる

開発中のローカルでの動作確認時に、Renderer側はどこにあるファイルを読みに行くべきか、は少し悩みました。
Node.jsでのアプリ開発ではNODE_ENV環境変数で動作モードを切り替える、という手法がよく使われるので、developmentモードを指定した場合はローカルにあるファイルを、productionモードを指定した場合はWebに配置したファイルを読む、というようなことは少し考えました。
しかし、これは以下の理由により避けました。

  • Rendererはローカルファイルを読む場合とWebから読む場合とでは動作が異なる(前述のSame Origin Policyなど)ため、日常的にWebから読む状態で開発しないと、いざリリースするときに想定していなかった問題が発生する恐れがある
  • developmentモードかproductionモードかは、ファイルをどこから読むかとは別問題

というわけで、開発中でもWebサーバーを立ててファイルをホストさせ、Renderer側はそれを読み込みに行くようにしました。

Webサーバーを立てるツールは、以下のようにしました。

  • developmentモードの場合:webpack-dev-server
  • productionモードの場合:http-server

webpack-dev-serverは一般的なフロントエンド開発でもよく使われるツールです。hot-reloadを有効にすれば、Electronであってもコードの変更時に自動的にリロードされるため、便利でした。

http-serverは、Node.js製の、手軽にWebサーバーを起動できるCLIツールです。

www.npmjs.com

productionモードの場合、実際のリリース物と同じビルドとなるため、webpack-dev-serverを使うのは適切ではありませんでした。
代わりに、webpack-dev-serverと同様にコマンドで起動して手軽に使える、http-serverを採用しました。

ローカルでの動作確認用にアプリとWebサーバーを同時に起動する

前述のように、開発中であってもWebサーバーを立てる構成としたので、動作確認の際には、ElectronアプリとWebサーバーの両方を起動させる必要があります。 ElectronもWebサーバーも、プロセスが端末を占有してしまうので、それぞれを起動させておくために端末を2つ立ち上げておく必要があります。
しかし、このような操作が必要な場合、以下のようなミスが発生しやすくなります。

  • なぜか動かないと思ったら、Webサーバーが起動していなかった
  • なぜか動かないと思ったら、Webサーバー側でエラーがでているのに気づかなかった
  • ElectronとWebサーバー、両方の再起動が必要なのに、それを忘れ、うまく動かなかった

いずれも些細な問題ではありますが、発生頻度がそこそこ高く、開発速度の低下につながるため、早めに対処しておきたいところです。

どのように対処するかというと、要するに以下のようなことが実現できていればよいと考えました。

  • コマンド一発でアプリとWebサーバーが両方起動すること
  • アプリを終了したら、Webサーバーも終了すること

上記を実現するため、今回はConcurrentlyというCLIツールを利用しました。

www.npmjs.com

このツールは、複数のコマンドを並行して実行できるため、この問題の解決にピッタリです。
このConcurrentlyを使い、アプリの起動コマンドを以下のように作成しました。

concurrently -k “run_server” “run_app” || exit 0 

上記のコマンドでのポイントは以下です。

  • -kオプションを付与すると、起動したいずれかのプロセスが終了すると、他のプロセスも終了するため、アプリを終了したらWebサーバーも終了させることができる
  • -kオプションによる終了はエラー終了扱いになり、エラーが出力されて気持ち悪いので、exit 0を直後に実行して、終了コードを強制的に正常終了にする

このようにすることで、Webサーバーの存在をほとんど意識せず、アプリの動作確認を行えるようになりました。

アプリからの参照先Web環境を切り替える

一般的なWebアプリを開発する場合、開発/ステージング/本番のように、用途ごとに環境を使い分けることはよく行われます。
Webアプリの場合は、ブラウザに入力するURLをそれぞれの環境のものに切り替えれば済むのですが、Electronアプリはアプリ内に参照先のURLを持たせなければならないため、Webアプリほど簡単に環境を切り替えることができません。

Electronアプリが参照するURLを切り替える方法を考えたとき、真っ先に思いつくストレートな方法としては、設定ファイルにURLを記載し、アプリはそれを参照してURLを取得する、というものがあります。
しかし、これは以下のような理由で避けることにしました。

  • ユーザーによって値を改変されたくない:もしユーザーがファイルの内容を書き換えたりしてしまった場合、アプリが動作しなくなる恐れがあります
  • ユーザーが普通に見える場所に値を置きたくない:URLや各種パラメーターが見えることで、アプリへの攻撃を行うヒントになってしまうかもしれません

ただ、個人的にはそもそも環境の値が可変値なのがしっくりこなかったのが理由としてあります。アプリ本体とWeb側は一体のものであり、Web側はパラメータとして気軽に差し替えするようなものではないと考えました。

結果として、アプリをビルドする際に、Web側の環境を埋め込むことにしました。
以下に、環境を決定する仕組みを示します。

まず、ビルドを行うコマンドを実行する際に、環境変数で参照先の環境を指定します。
ここでは、DEPLOY_ENVという環境変数で、環境指定を行っています。

DEPLOY_ENV=development npm run build

アプリのコード内では、上記の環境変数で指定された値に対応する環境設定ファイルをrequireするようにします。
環境変数は、WebpackのDefinePluginを用いてビルド時に埋め込みを行っています。

require(`./${DEPLOY_ENV || "development"}`)

以上の仕組みにより、ビルド時に例えば"development.js"のようなファイルが結合され、アプリ内に環境の値が埋め込まれるようになります。

参照先Web環境を上書きする

前述の仕組みにより、参照先の環境の問題は解決したと思ったのですが、開発工程の中で「本番環境向けのビルドを開発/ステージング環境へ向けるようにしてテストしたい」という要望があることがわかりました。
要するに、本番環境向けビルドと開発環境向けビルドは、同じソースからビルドしていても別物なので、開発環境向けビルドをテストしても、本番環境向けビルドをテストしたことにはならない、ただし本番環境でテストすることは避けたい、という理屈です…。

これを解決するため、特定の位置に設定ファイルがあれば、そこに記載された値をアプリに埋め込まれた設定値よりも優先する、という機構を追加しました。
先ほど「設定ファイルを避けた」と述べましたが、これは開発中のリリース前テスト等の工程で利用するものであり、ユーザーが使う機構ではないため、設定ファイルを回避した理由は維持しているつもりです(;・∀・)
なお、弥生の他の製品でも、実際にこのような設定の上書きを行うような機構を使ってテストを行っています。

おわりに

ElectronアプリのRenderer側をWebに配置するようにする際、どのような変更を行ったかについてご紹介しました。
同様のことでお困りの方の助けになれば幸いです。

明日は@t_haraさんの「Swift製ファミコンエミュレータ開発の進捗について書く」です。楽しみですね!