Mikimemo

個人的な技術・開発メモやポエム

息子が生まれた技術ポエム

先月第一子が産まれました。それに伴い会社の方も育休を取らせてもらっています。

そして本日3/1はCTO就任から1年の節目でもあります。実際はお休み入って11ヶ月間の業務ということになりましたが、1年間取り組んだこと等に関しては育休復帰後に会社ブログなどで振り返り・紹介できればと思っています。

そんなこともあり、今まであんまりポエミィなことは書いて来ませんでしたが今日は記事にしてみます。あんま脈略がない自分語りが多めです。

育休について

まず、育休はとってよかったと感じています。というより、ここ3週間、都内で自分と妻の2人での育児オペレーションで育休取らないと回らなかったと思います。専用の時間を確保できたことで育児・家事にかなり集中できたと思います。

再度ですが協力いただいているチームメンバーに感謝です。うちの会社は育休の取得に関してすごい前向きでとてもありがたかったです。

育児もオーナーシップが大事だなと。自分一人でワンオペするとしたらどうすべきなのか、調乳の方法・原理、沐浴の方法、ミルクの量の意思決定を一人で下せるのかなど、生まれる前や、無事生まれたあと、深夜番の隙間に教本とかYouTubeとか調べて、Try&Errorしてました。この期間は、そういう育児ナレッジ・技法習得するために時間をたっぷり使えてました。世の中の夫は産後の妻にむしろやり方や情報を教えるくらいの意識でいるのがちょうどいいんじゃないかなとも思いました。

単純な育児作業だけでなく、病院や区役所手続、両親が家にくるなど結構バタバタするので、その辺りゆったりと時間使えたのはよかったです。

育休時間の+α

育休に入って多少身の回りのことや自分のことを整理するきっかけになりました。ある意味、大学院から社会人とにかく走ってきたという感じで、やりたいこととか、調べたいこととかができずフラストレーションが溜まっていたんですが、逆にちょっとした待ち時間や隙間時間で消化できているのでは?という感じです。今回のポエム記事もその一環です。

まぁ、もともと面倒くさがりで休日YouTubeNetflixで消費することも多かったんですが、やっぱり会社のマインドシェアが高く、退勤後や休日も、あの課題にはどう対処しようかなとか、あの案件の確認を月曜の朝イチでしようとか考えているんですよね。一旦そこから離れられていると思います。

こういうことをするぐらいには、まだ余裕はあります(今後はわからないが...)

頭パンパンな状態で何か進めるより、一旦落ち着いていろいろ考えてみるというのは良いなと思ってます。

自分とエンジニアリング、ここ10年

自分は大学院では音楽情報処理という分野を研究していて、音響解析とか、データマイニングとか、クラスタリングとか、まぁそういうことをしてました。そこの研究でウェブの技術を使ってああ面白いなと思い、Web的な業界に入りました。

当時はWebブラウザソーシャルゲーム全盛かつスマホへの移行が始まったばかりで、自分はもともとiアプリのゲームを個人開発していたり、研究でiOSネイティブアプリを開発したりしていたこともあり、ゲームxモバイルの業務を担当していく中でゲーム業界・ゲームエンジニアという道やキャリアを歩むことになりました。ただし、ゲーム開発一編というより、その出自から(エンターテインメント)サービスや事業をやりたいというのが根底にあります。

その中でも大きかったのはUnityとの出会いです。たまたまCEDEC2011のUnityセッション(高橋啓治郎さんの)をみて、会社でそれに取り組むことになって、3Dグラフィックスなんて右も左もわからないまま調査して、プロダクトを作ってみたいな感じでした。

そうこうしているうちにいつの間にか会社でもUnityに詳しい人になってて、商業誌でこちらの「Unity5 3D/2Dゲーム開発 実践入門」を書きました。実は重版が8回もされて、多くの方にご贔屓いただいたのはとても嬉しかったです。

www.socym.co.jp

その後も、Unityのバージョンに伴い手順やトピックに追従する改訂を続けています。↓↓↓

Amazon.co.jp: 吉谷 幹人: 本

本に関しては、新卒の時に自分のエンジニアとしてのマイルストーンとして「何かのスペシャリスト・第一人者になって本を書く」と言ったことを当時の上司の方が聞いてくださっていたみたいで、執筆のお話をいただきました。なので、若いエンジニアの方はそういう目標とかを常々言っていると良いのではないかなと思います。

で、UnityをやりつつRailsでのバックエンドやりつつ、テックリードとしてPMっぽいことやEMっぽいことももやりつつ、徐々に見る範囲・影響を出すべきスコープが大きくなって、今はCTOというロールを頑張ってます。

今の自分と成長・危機感

ここ数年、確かに自分も成長してます。ただ純粋に技術を極めるという感じの成長感ではないです。やはり最近だと、組織マネジメントや課題解決、経営・ビジネス的な視点、プロジェクトマネジメント手法、チームとしての技術の強み作り...とかの面で視野や影響範囲が広がったなというかんじです。どうやったら上手くいくのか、組織として継続性を持たせられるのか、組織としてのゴール・ミッションを達成するためのあらゆる方法を技術的な観点踏まえて実行していくという考えが第一に走ります。

いろいろなタイプの技術リードがいると思いますが、その中でもマネージャーなどのジェネラリストっぽいキャリアと、技術にコミットしていくスペシャリストっぽいキャリアと大分されることが多いと思います。EMなどの組織マネジメントをする人がVPoEに、スペシャリストがCTOみたいな感じっぽく見えますが、そんなこともないように思います。

CTOとしては組織も技術もマネジメントもするし、ある意味、スペシャリストの中のジェネラリストみたいな感覚があります。インディビジュアルコントリビューター寄りの、技術で組織引っ張ってくタイプの方もいらっしゃるのかもしれませんが、少なくとも自分は、超技術特化タイプというよりは幅広タイプという感じがします。

やはり、組織全体をを見ていく中でクライアントもサーバーもインフラも設計も技術選定もAccountabilityを持つということで意思決定や結果を説明できる状態じゃないといけない。技術詳細や実行は委任するにしろ、少なくともその技術領域がどういうものかを理解する必要があり、そう言った点でも幅広さはあっても浅い感じになってます。

この、成長はしているが、純粋な技術者として相対的に浅くなっているということが、やはり自分としての危機感です。

今後の10年は

自分はもともと職人タイプのエンジニアで、完璧主義・仕事は技術と成果で語る的なフシがあり、アピるのが結構苦手です。無口なラーメンの店主タイプ。なにか作ること自体が好きでそこで満足しちゃうとこもあります。嫁になんかやったんなら発信しなさい!!とよく怒られます。

ただ、会社とか関係なく一人のエンジニアとして、今後発信していかんといけんし、そこのマインドを変えていかないといけない。

それと、マネジメント的な知識、スキル、経験、幅広さは今後も強めていくとして、純粋な技術的な強みを少なくともあと2軸は持たないとやっていけない気がしてます。今Unityとか設計はまぁそれなりにできますよ、と人に言えるけど、これをあと2つぐらい作りたい。

最近やっぱり目の前の課題解決に集中していたので、インプットが圧倒的に足りないないなと思っています。今後は自分だけの時間なんてもっと減ると思うけど上手くバランスと取っていきたいです。

*さっき妻に1周年記念花束もらいました。サンクス〜!

シンプルなDAppを手元で試してテストネットまでデプロイしてみる【社内ハッカソン】

5/14に久しぶりに社内ハッカソンがありました。 コロナなどの影響で2年ほど見送りが続いていたんですが、 運営委員を再編するところから小規模ながらようやく開催できました。

ハッカソンといっても各自好きなこと・目標を決めて1日集中して何か成果物を作るみたいな感じなので、 今回は前から気になっていたDApps/ブロックチェーン周りの技術に触れてみることにしました。

もし、自分も気になっているな〜という方がいたら同じ手順を踏んでもらえると感触をつかめるかもしれません。

今回の記事についての注意点: 筆者の理解がまだ浅いことと、1日の中での調査のため、正しくない説明や記述がある可能性があります。

今回の目標

  • Web上で公開されているシンプルなアプリをCloneしてきて内部構造やContract、front-endのコードを読む
  • そのアプリを手元でコンパイル、ローカルのネットワークに接続してトランザクションなどの動きをみる
  • シンプルなアプリを修正できるところがあれば簡単な修正・カスタマイズを加えてみる
  • アプリをテストネットワークに繋いでそこでトランザクションを実行してみる(front-endはローカルで起動)

当日までに済ませていたこと・事前準備

以前から少しだけブロックチェーン・暗号通貨周りのあれこれを試したりしてましたが、 それに加えて簡単な勉強などを事前準備として行っていました。

MetaMaskのインストールや暗号通貨の送金など

この辺は2018年のCyptoKittiesで遊んでみた記事でやってました。

なんか技術書読む

これもだいぶ前だったと思うのですが、とりあえず以下の書籍を読みました。 全体像がつかめてよかったです。

Axie Infinityやってみる

去年だいぶ話題だったAxie Infinityをやってみました。 CyptoKittiesの時よりも、ブロックチェーン周りのエコシステム・Play to Earnみたいなところを体感できたきがします。

axieinfinity.com

CryptoZombiesでSolidityの勉強

Solidityの勉強のためにCryptoZombiesのプログラムを途中までやりました。 CryptoZombiesすごいわかりやすいし楽しいです。

cryptozombies.io

TODOアプリ起動確認・ローカルネット確認編

とりえあず、当日の流れやポイントを紹介していきます。

当日の前半戦は、以下の記事を参考にさせていただきました。 とてもわかりやすいハンズオン記事感謝です。 zenn.dev

サンプルアプリのリポジトリも公開されているので、実装手順は後日ゆっくり試してみることにして、 コードと構造を確認後、完成形を動かすところからやってみます。

nodeとかをinstallするのは省略です。

とりあえずパッケージinstallします。

$ yarn install

つぎに早速コントラクトをコンパイルしてみます。

$ npx hardhat compile
Compiling 1 file with 0.8.4
Generating typings for: 1 artifacts in dir: typechain for target: ethers-v5
Successfully generated 5 typings!
Compilation finished successfully

無事とおりました。

成果物がartifacts以下に出力されます。

$ ls artifacts/contracts/TodoList.sol
TodoList.dbg.json   TodoList.json

出力されたTodoList.json はABI(Application Binary Interface)と呼ばれ、 front側から呼び出す時のインターフェースになるっぽいです。

次にローカルのネットワークにノード立てます。

$ npx hardhat node
npx hardhat node
Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/

Accounts
========

WARNING: These accounts, and their private keys, are publicly known.
Any funds sent to them on Mainnet or any other live network WILL BE LOST.

Account #0: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 (10000 ETH)
Private Key: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80

Account #1: 0x70997970c51812dc3a010c7d01b50e0d17dc79c8 (10000 ETH)
Private Key: 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d
...

無事ネットワークが立ちました。 初期のアカウントのアドレスと秘密鍵が20個表示されてます。

ネットワークはhttp://127.0.0.1:8545/をエントリーにいろいろ通信できるみたいです。 立ち上げたコンソールはそのままにしておきます。

さて、ローカルのネットワークはたちましたが、特に何も動いてないので 先ほどコンパイルしてみたコントラクトをデプロイします。

$ npx hardhat run scripts/deploy.ts --network localhost
localhost
No need to generate any newer typings.
todoList deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3

デプロイできました。 デプロイ後コントラクトのアドレスが表示されます。 このアドレスはweb-front側で利用しています。

このとき、立てっぱなしにしていたネットワークのコンソール側にもログがでます。

web3_clientVersion (2)
eth_chainId
eth_accounts
eth_blockNumber
eth_chainId (2)
eth_estimateGas
eth_getBlockByNumber
eth_feeHistory
eth_sendTransaction
 Contract deployment: TodoList
 Contract address:  0x5fbdb2315678afecb367f032d93f642f64180aa3
 Transaction:     0x376862b3b1bc5fa66710ca238c5ed4f1189c05d46f9a09058b1fffa2ee3b7bb4
 From:        0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
 Value:        0 ETH
 Gas used:      631868 of 631868
 Block #1:      0xf416cd7e33b9960166ece22b4c936aecad62c02888f7fcba585ce7dce76491a4

eth_chainId
eth_getTransactionByHash
eth_chainId
eth_getTransactionReceipt

次にfront側たてます。 web3.jsが使われるのかなーとおもっていましたが、最近はethers.jsが主流なんですかね? web-frontディレクトリに移動してfront側のパッケージをinstallします。

$ cd webfront
$ yarn install

frontを立ち上げます。

$ yarn dev

いい感じに立ち上がりました! 実際にCreate Taskなどを押すと、ネットワーク側のトランザクションのログなどが流れるのを確認できます! うーんいいですね。

Web3Providerへの変更とconnect編

さて、いったん動きを確認できましたが、ここで疑問がでました。 そもそもコントラクトとしてはviewだけなら特にgas代はかからないが、 書き込みのTransactionはgas代がかかるはず...そもそもMetaMaskなどやアカウントとの連携はどうするんだ? というとこです。

これはApp.tsxのproviderを取得しているところの修正が必要なのかなと。

export const App: VFC = () => {
  const provider = new ethers.providers.JsonRpcProvider();
  const signer = provider.getSigner();
  const contract = new ethers.Contract(contractAddress, artifact.abi, provider);
  const contractWithSigner = contract.connect(signer);

JsonRpcProviderはデフォルトではhttp://localhost:8545につながりにいくんで、 そこでローカルのネットワークに接続して、getSignerでindex 0のAccount #0: 0xf39fd6...を引っ張ってくる。 これはわかるが、なんかノーコストでトランザクション動かせるのはなんでなんだろ? ここはちょっとよくわからなかった。

ひとまず、テストネットではこうはいかないと思うのでWeb3Providerに変えてみます。

const provider = new ethers.providers.Web3Provider(window.ethereum);

これでMetaMaskと連携できるはず。

試す前にMetaMaskをローカルネットに接続しておきます。 今回は元々MetaMaskで利用していたアカウントを使ってみます。 MetaMaskのネットワーク切り替えメニューの下部にネットワークを追加というメニューがあるのでそこから追加します。

RPC URLは先ほどローカルネットワーク立てたときに表示されたやつですね。 チェーンIDはどこで確認するかわかんなかったんですが、URLなどを入力したら自動で入りました。 多分定型で31337っぽいです。 通貨記号はテスト用はGOと設定するのが良いっぽいのでそうしました。

これでMetaMaskにローカルネットワーク追加できました。

このアカウントの残高はローカルネットワークでは0(GO)です。 このままでは検証ができないので、以下を参考に初期アカウントから送金するのを試してみました。

zenn.dev

以下をscripts/sendGasFee.tsを作成します。

import { ethers } from "hardhat";

async function main() {
  const transactionSend = {
    to: "0x.....[送信先アカウントアドレス]",
    value: ethers.utils.parseEther("10.0"),
  };

  const [account] = await ethers.getSigners();
  await account.sendTransaction(transactionSend);
  console.log("success");
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

以下を実行します。

$ npx hardhat run scripts/sendGasFee.ts --network localhost

送金できてますね!

さて、これでもうちょい本格的に試せると思ったんですが、ちょっと問題が。 web-frontのページにアクセスしてもMetaMaskが反応しないんですよね。 MetaMaskの左側は未接続と表記が。 確認すると接続ボタンを押してくださいとでます。

なるほど。確かに各種サービスにそういうボタンあります。 ということで以下を参考させていただき修正してみました。

developers.gmo.jp

以下を呼び出せばいけそうです。

const account = await window.ethereum.request({ method: 'eth_requestAccounts' });

とりあえず、コードを修正して呼びだすようにして、無事接続できました。

とりあえず、接続したことでコントラクトからのデータ取得も再度正常にできるようになりました。 この状態で再度トランザクションを実行してみます。

書き込みを実行するとMetaMaskが起動します! gas代も表示されます。それっぽいです!

MetaMaskの確認を承認すると、TODOリストにTaskが書き込まれ、実際にアカウントの通貨量もgas代として減ってます。

しかし、ネットワークのログを見ると以下のログがでていました。

Error: Transaction reverted: function selector was not recognized and there's no fallback function
....

これはTodoList.sol側にrecieveとfallbackのメソッドを実装したら出なくなりました。 techblg.app

ただ、コントラクト側に変更を加えて再度デプロイしたら別アドレスになってしまい、 storage値なども引き継がれてないので、どうマイグレートするといいのか、他のデプロイ方法があるのかはちょっと調べられませんでした。 今回はテストなので問題ないですが。

Counterアプリ起動確認編

この辺りで当日の成果物どうしようかなという感じに。 一旦全般の流れは確認できたのですが、 いかんせん自分がreactとかに詳しくないこともあり、 もっとシンプルなアプリの方が、なんか弄りやすそうな気がしてきました。 あと、デモ的にもそっちのほうがウケがよいかなと。

ということで、後半はこちらのカウンターアプリの手順を追うことに(こちらも記事公開ありがとうございます)。 zenn.dev

connectボタンの処理も実装済みです。 実はfront側にコントラクトeventのコールバックも実装してあるので、 トランザクション完了のタイミングなどを正確に取得して画面更新などが走ります。

手順を追う部分は省略しますが、 こちらも公開されているリポジトリからパッケージインストール、コントラクトコンパイル、デプロイ、フロント起動という順で試しました。

また、先ほどのTODOアプリの同様にトランザクション時にエラーがでたので、recieveとfallbackのメソッドを実装しました。 さらに、今度は既存アカウントに送金するのではなく、 記事の手順通りローカルで発行されたアカウントをMetaMaskにインポートすることで残高がある状態にしてみました。

テストネットデプロイ編

2つのサンプルアプリを触ってだいぶ理解も進んできたので、当初の目標であるテストネットワークにデプロイするところを目指すことに。 これでデモ的にもハクがつくでしょう。 Ethereumのテストネットワークの一つであるRopstenにデプロイしてみます。

まずはですが、先ほどと同様にMetaMaskの接続先をRopstenネットワークに切り替えます。 なんか選択肢に出てこないなーとおもったらMetaMaskの設定->高度な設定にテストネットワークを表示するオプションがありました。

このオプションを有効にすると普通にネットワーク切り替えにでてきました。

次にテスト用のEtherをFaucetに要求します。こちらを参考にしています。

zenn.dev

最初どこからだ?とまよったんですが、 Ropstenネットワークに切り替えた状態で、 Metamaskの「購入ボタン」を押すとでるメニューの下部スクロールしたところにありました。

その先に進んだrequest 1 ether from faucetボタン押すとトランザクションを発行できます。 テストネットワークといえメインネット同じPoWでコンセンサスアルゴリズムが走るので、 完了まで1~2分ほど若干時間がかかります。

ちなみfaucetのページにtransactionのリンクが表示されるので、etherscanで内容確認できます。

次は、実際にRopstenネットワークにデプロイします。 デプロイのためにINFURAに登録します。 infura.io

プロジェクトの情報を入力したら設定画面にて、 ENDPOINTSの項目でRopstenを選択しhttps://ropsten.infura.io/v3/〜の部分をメモります。

さらに、サンプルのカウンターアプリのpackages/contract/hardhat.config.jsを以下のように修正します。 アカウントのPrivateKeyはMetaMaskのアカウントの詳細->秘密鍵のエクスポートから取得できます。 絶対に流出(どこかに載せたり、リポジトリにコミットしたり)しないようにしましょう。

require("@nomiclabs/hardhat-waffle");

module.exports = {
  solidity: "0.8.0",
  networks: {
    ropsten: {
      url: "https://ropsten.infura.io/v3/[メモしたENDPOINTS URL]",
      accounts: ["MetaMaskで管理してるアカウントのPrivateKey"],
    }
  }
};

これで準備は整いました。 ネットワークを指定してデプロイします。

$ npx hardhat run --network ropsten scripts/deploy.js
deployed to: 0x36d7A108c6877Fa15D31275e890C9706452ADE51

デプロイが完了すると、gas代としてアカウントのETHがちゃんと減ってます。

またINFURA側のダッシュボードにもアクセスあることが確認できます。

よし、、、 ということで、本日の成果物、 gas代を払って数字を上げ下げする、その名も「Super Counter」が完成しました。(ほとんどコーディングはしてない)

なお、検証が目的なのでfrontはローカルで立てるだけでどこにもデプロイしてません。

まとめ

久しぶりのハッカソンたのしかったです! DApps/スマートコントラクトという概念に触れるのは、ちゃんと動くアプリケーションのレベルでは初だったので新鮮でした。 バックエンドにRDBのようなものが一切ないのに値が保存されているのは、なんか感慨深いですね。 新しいパラダイムに触れるのはプログラムを始めた時から、いつになってもワクワクします。

世間ではNFTとかもろもろ、投資、投機的な側面が強調されていいるような印象もあり、 記事を検索しても技術記事と混在しているような感じもします。

いわゆるweb3と呼ばれるサービスやシステムが、 既存の集中管理型のサービスの置き換えになるわけでもなく、 front-endが必要ないわけでもなく、 技術的な側面を見ると本質的にはどういう優位性があるのか?と疑心暗鬼になる気持ちもわかります。

ただ、アプリケーションやトークンが外部経済との接続を持つという点だったり(投機的目線の理由である通り)、 トランザクションの透明性だったり、 その上でそれらの手続きが自動実行可能など、 新しくできることの可能性が増えたのだなという感じがします。

どこかでweb1はread、web2はread-write、web3はread-write-ownと聞いて、 なるほどなーと思ったのですが、 それも踏まえてweb3やDappsは「価値」を扱っていくのが本質なのかもとも感じました。 人やコミュニティに応じて色々な価値基準がありますが、そいういうがいろいろ繋がってくんのかなというか。

と、ちょっとまとめでわかった風に書きましたが、 まだまだ理解が足りてませんので、引き続きいろいろ勉強したいと思います。 本質を理解してこれらのパラダイムで何か新しいものを生み出してみたいですね。

ポートフォリオっぽいサイトをGitHub Pages + Jekyll構成に移行した話

久しぶりの投稿です。

今回、個人の実績とかを集約していたサイトをリニューアルしたので、その手順をメモしておきます。

このサイト自体は大学院の研究室の都合で作成したものだったのですが、 その時々の技術的な流行をちょっと試してみるみたいな趣旨もあり、 構成もHerokuやAWSと10年の間でいろいろ変遷してきました。 完全にオーバースペックなので、もっと一般的な手法に切り替えます。

なお、移行とリニューアルが完了したサイトは以下になります。

https://mikinya.net/

今回の動機

今回、サイトを移行・リニューアルするモチベーションをまとめると以下になります。

  • 勉強のためにnode.jsやAWS、コンテナを使っていたが、今は目的を果たして単にオーバースペックで複雑
  • 特に専用のフレームワークなどは活用してないのでページ追加がやりにくい
  • もはやBootstrapが古く見えすぎる
  • 極微量な料金だが、無料でできるのなら節約したい

ということで、単にインフラのレイヤーを移行するというより、 見栄えやフレームワークまで意識していく流れです。

前回までの話

当該サイトは2019年1月にHerokuの環境からAWS/Docker/Elastic Beanstalk環境へ移行しました。 その時の記事がこちらです。

mikimemo.hateblo.jp

*ちなみに上記記事のFargateの見解はおもいっきし間違いです。そもそもFargateはコンピューティング・リソースを提供するもので、単純にECSとかと比較するのは検討違いでした。

約3年この構成で動いていたのか... 実は去年RIの購入とかもしていたりして、とても勉強になりました。ありがとう旧構成。

作業の方針

色々調査した結果、 GitHub PagesJekyllを利用することにしました。

Jekyllはマークダウン記法のドキュメントなどから、 いい感じに静的なWebサイトをジェネレートしてくれるライブラリです。

もともと、簡単にWebコンテンツをホスティングできる、かつ独自ドメインも設定可能な GitHub Pagesを利用しようとは決めていたのですが、 ドキュメントを読み進めていくうちに、Jekyllというものを知り、いいやん!となりました。

メモ: 静的サイトジェネレーターは世の中にたくさんあると思いますが、 今回はGitHub Pagesが公式対応しているのでJekyllにフォーカスです。

こちらの比較記事参考になります。

プロジェクト生成、ローカル確認

GitHub側のリポジトリ作成などは、済ませているとしてローカルにJekyll環境を構築してきます。

基本GitHub PagesやJekyllの公式手順に従っていきます。

docs.github.com

jekyllrb-ja.github.io

まずは、ローカルにリポジトリ用のディレクトリ作ります。

$ mkdir my-site
$ cd my-site

*ライブラリ開発とかですでにリポジトリ内に何かある場合はorphanブランチとかに作ったりすると良さそう

初期化に必要なgemをインストールして初期ファイルを生成します。

$ gem install bundler jekyll
$ jekyll new --skip-bundle .

Gemfileのjekyllの部分をコメントアウトしてgithub-pagesの項目に変更します。 このとき223のところはこのページから都度対応している最新バージョンに置き換えてくれとのことです。

#gem "jekyll", "~> 4.2.1"
gem "github-pages", "~> 223", group: :jekyll_plugins

これでbundle installします。

$ bundle install

完了したら以下でローカルサーバーを立ててみます。 http://localhost:4000にアクセスすると、それっぽいサイトが立ち上がっていることを確認できます。

$ bundle exec jekyll s

f:id:miki05:20220228205505p:plain

リモートでの確認

一旦この辺りでremoteにpushしてGithub Pagesの動作を確認してみると良いでしょう。 ただし、GitHub Pagesのデフォルトでは以下みたいな感じでサブフォルダにホストされるため、 あらかじめ設定をしておかないと、うまく表示されないケースがあります。

https://account-name.github.io/repo-name/

これらの設定のためにプロジェクト直下にあるconfig.ymlを編集します。 Jekyllではこのconfig.ymlがキモで、 このファイルに様々な定義や設定を指定することで、 全体の見栄えや動作をカスタマイズしていきます。

以下の項目を修正します。

url: https://[GitHub Account Name].github.io
baseurl: /[Repository Name]/

最終的には独自ドメインを設定するので、この設定は不要なのですが、 一時的に設定して、サイトの移行準備が完了したら再度修正します。

ちなみにですが、リポジトリのRoot DirectoryにREADME.mdを配置していると、 GitHub Pagesにデプロイした時、なぜかそれをトップページみたいな感じで認識されます。

こちらは_config.ymlのexcludeの項目のコメントアウトをはずしてREADME.mdを追記するとJekyllの処理対象外にできます。

exclude:
  - .sass-cache/
  - .jekyll-cache/
  - gemfiles/
  - Gemfile
  - Gemfile.lock
  - node_modules/
  - vendor/bundle/
  - vendor/cache/
  - vendor/gems/
  - vendor/ruby/
  - README.md #追記

自分の場合、作業観点でのmemoなどをREADMEに残しておきたかったので、このような処置をとりました。 Jekyllの構成フォルダをサブフォルダとかに切り出す設定なども試しましたが、あんまりうまくいかなかったです。

テーマの設定

Jekyllはサードパーティ製のものも含めてさまざまなテーマを利用できます。 今回は一番スターがついていて良さそうな感じのMinimal Mistakesを利用することにしました。

mmistakes.github.io

またテーマのライブラリごとにお作法が変わってきたりもするので、 以後はMinimal Mistakesのドキュメントも必読です。

とりあえず、テーマ導入します。 複数の方法があるようですが、今回はremote_themeを利用する方法にします。

ますGemfileに以下を追記してbundle installします。

gem "jekyll-include-cache", group: :jekyll_plugins

次に_config.ymlを修正します。skinも選べるので後でゆっくり検討するとよいです。

# theme: minima # 消す 
remote_theme: mmistakes/minimal-mistakes@4.24.0
minimal_mistakes_skin: "default" #"air", "aqua", "contrast", "dark", "dirt", "neon", "mint", "plum", "sunrise"

plugins:
  - jekyll-feed
  - jekyll-include-cache # 追加

多分これでサーバー立て直すとテーマが適用されているかと思います。 ちなみに基本Jekyllはコンテンツを修正すると自動でhtmlファイルなどを再ジェネレートしてくれるんですが、 configファイルを修正したときはサーバー再起動が必要のようです。

f:id:miki05:20220228205603p:plain

レイアウトとFront Matter

テーマを変更後、サーバーのたてる時にいくつかのワーニングがでており、 例えばabountなどのページがうまく表示されなくなります。

これは、デフォルトのテーマではpageというレイアウトが存在していたのですが、 Minimal Mistakesに変更したことでそのレイアウトが存在しなくなってしまったためです。 これらのレイアウトは各マークダウンファイルの冒頭で指定ができます。 layoutでpageが指定されているところをsingleに変更します。

---
layout: page # -> single
title: About
permalink: /about/
---

# 本文...

この冒頭のハイフンで囲まれた領域をFront Matterと呼び、 ページごとにさまざまな指定ができます。

config.ymlなどをいじくる

この辺りで_config.ymlやファイル構成を用途に合わせて修正していきます。 今回はabout.markdownやpost(ブログのような記事を管理できる機能)などの要素は不要のため、ファイルを削除しました。 また.markdownの拡張子も.mdに統一しました。

Authorの表示

今回はポートフォリオサイトみたいなものを作りたいので、自分の情報を表示するために Authorの機能を利用しました。これを使うとページの左側に情報を表示することができます

以下のように_config.ymlに追記します。

author:
  name: "Mikito Yoshiya"
  avatar: "/assets/img/avatar.png"
  bio: "Software Engineer"
  location: "Tokyo, Japan"
  links:
    - label: "Blog"
      icon: "fas fa-fw fa-link"
      url: "https://mikimemo.hateblo.jp"
    - label: "Twitter"
      icon: "fab fa-fw fa-twitter-square"
      url: "https://twitter.com/mikito0521"
    - label: "Facebook"
      icon: "fab fa-fw fa-facebook-square"
      url: "https://www.facebook.com/mikito.yoshiya"
    ...

画像などのファイルはassetsなどのフォルダに配置しておけば、 Jekyllが自動的に認識して、成果物フォルダである_siteにコピーし参照できるようにしてくれます。

ちなみに各サービスのアイコンはドキュメントにもありますがこちらで利用可能なものを検索できます。

この設定後各ページのFront Matterで

author_profile: true

とすると、有効になります。

defaultsの設定

author_profileの設定は各ページのFront Matterで指定すれば有効になりますが、 全てのページで指定するのは面倒です。

config.ymlではパスごとにFront Matterのデフォルト値を設定できます。 基本的なページではauthor_profileを有効に、layoutはsingleを利用するようにしておきます。

defaults:  
  - scope:
      path: ""
      type: pages
    values:
      layout: single
      author_profile: true

Feedはいらない

今回はFooterのRSSフィードのリンクは不要だったので、 以下のように非表示しました。

atom_feed:
  hide: true

その他

その他navigationとかfooterとかめちゃくちゃ機能があるのですが、 公式ドキュメントを読みながら進めるのがよいと思います。

今回は、超シンプルなサイトを構築するのが目的のため上記あたりの設定で完了です。

あとはindex.mdとか必要なページをマークダウンで記述していきます。 この辺りのドキュメントも参考になります。

独自ドメインの設定

基本はGitHub Pagesの公式手順に従っていきます。

GitHub上でSettings->PagesのCustom domainに取得済みドメインを入力してSaveを押します。 そうするとリポジトリにCNAMEという名前のファイルが自動的にコミットされます。

次にDNS側の設定をします。 自分の場合ドメイン自体はお名前.comで取得しています。 また、旧構成ではAWSのサービスに管理を寄せており、 DNSサービスにRoute 53を利用していたのですが、 そちらでの管理は廃止しお名前.com側に登録するようにします。

これに関しては、こちらの記事を参考にさせていただきました。

上記の手順だけでは、Github Pagesがワーニングを吐いてきたので、 お名前.comのインターフェースからwwwサブドメインのCNAMEレコードも登録しました。

CNAME www.my-site.net github-account-name.github.io

設定が完了しGitHub Pages上でcheckがpassしたらEnforce HTTPSも有効にしておきます。

faviconの設定

一応ですがfaviconの設定もしました。

faviconっていまの世の中すごい面倒なことになってるんですね... faviconを設定するためにはJekyllのレイアウトテンプレートを修正する必要があるんですが、 そこにはrealfavicongenerator.netというサービスを使ってくれと記述されています。

realfavicongenerator.net

こちらは一つのソースとなる画像をアップロードすると、必要な素材をプレビューしながら一括で作ってくれるし、 配置するためのコードスニペットも出力してくれるし、 さらにサイトのfaviconが様々なデバイスで正しく表示されるかをチェックしてくれるという神ツールです。

今回faviconも一新しようと思い新しく適当に書きました。 (今の自分はレベル1だけど簡単なベクター画像が描ける...!)

適用の手順はこちらを参考にさせてもらいました。

まず、リポジトリに_includes/head/というディレクトリを作ります。 そして、custom.htmlを配置します。 こちらは、本来ライブラリ側のソースをオーバーライドする形なのでリポジトリとかからコピーしてくるのが良さそうですが、 customと書かれているものはコメントのみのようなので、直接ファイルを作成しても良さそうです。

そして、そのファイルにrealfavicongenerator.netで出力された情報を貼り付けます。 この時、変換されたアイコン群は数が多いため、自分は整理の意味でassets/icon以下に配置しました。 そのため、hrefの部分を置き変えています。こちらの変更はbrowserconfig.xmlとsite.webmanifestの内容に対しても同様です。 また、browserconfig.xmlとsite.webmanifestに関してはその立ち位置上、サイトのルートに配置するようにしました。

<link rel="apple-touch-icon" sizes="180x180" href="/assets/icon/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icon/favicon-16x16.png">
<link rel="manifest" href="/site.webmanifest">
<link rel="mask-icon" href="/assets/icon/safari-pinned-tab.svg" color="#5bbad5">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="theme-color" content="#ffffff">

設置後https://realfavicongenerator.net/ でチェックします。 オールグリーンになればOKです。

旧環境のストップ

移行確認完了後、旧環境の停止作業を行います。

  • Route 53/ホストゾーン削除
  • Elastic Beanstalkの環境削除

Elastic Beanstalkに関してはDockerのプラットフォームが もれなくDeprecatedなってました。 今回の作業でこのような管理もフルマネージドに移行できるのはとても楽です。

その他、今回の作業の動機の一つですが、RIが2022/2/21で切れてます。 t3.nanoのRIなんて他に誰が使うんでしょうね...

コストとしては旧環境は合計で月$3.2程度でした。

その他の関連サービスも確認しましたが、問題なさそうでした。

  • EC2
  • ECS
  • ECR

作業を終えて、最後に

ひとまず移行とリニューアルが完了してひと段落です。 旧構成であるAWSサービスやコンテナを利用した取り組みは、とても勉強になるものでした。 ミニマムなものであっても実際に公開するところまでやっていくと、 ドキュメントを読むだけではわからない体験があります。

ただ、旧構成はコスト極限まで切り詰めるという方針から、 SSL証明書の管理周りがかなりテクっていて汎用性はなさそうでしたけど。

別の機会でAWSを使いこなして何かちゃんとサービスを自分自身で作ってみたいなーと思ったりしました (なかなか仕事では触れる機会がない)。

あとGitHub Pages、Jekyll、Minial Mistakesは可能性を感じました。 またどこかで活用する時がある気がします。

そして、サイト自体ですが、 本当は最初、学生時代の論文とか載せるのやめようかなと思ってましたが、 当時すごく頑張って仕上げた(&賞もいただいた)ことを思い出して、 引き続き掲載することにしました。

趣味で作ってたケーキ画像は廃止しました。

そして去年6月に執筆したUnity2021 3D/2Dゲーム開発実践入門のリンクも追記しました (ソシムさん全然宣伝できず、すみません。。。)。 こちら改訂作業も相変わらず苦労したので、ご興味あればぜひ覗いてみてください。

せっかくリニューアルしたのでポートフォリオを充実できるよう、 今後はもっともっとアウトプットしていきたいです!

Unity 3D/2Dゲーム開発実践入門の電子版が発売されます。無料試読版も配布!

先日発売・紹介させていただいたUnityの入門書 「Unity 3D/2Dゲーム開発実践入門 Unity2019対応版」の電子版が3/6に発売されることになりました! 紙の書籍と合わせて、こちらもよろしくお願いいたします。

Unity 3D/2Dゲーム開発実践入門 Unity 2019対応版

Unity 3D/2Dゲーム開発実践入門 Unity 2019対応版

また、本書の構成や内容をもっと知ってもらうために、 無料試読版をPDFにて配布させていただくことになりました! 以下からダウンロードができます。

bit.ly

無料試読版には以下の内容が含まれています。

  • はじめに〜目次
  • Chapter3-4:スクリプトによる重力の操作
  • Chapter4-6:エフェクトの表示(冒頭のみ)
  • Chapter5-3:3Dプレイヤーキャラクターの構築
  • Chapter6-3:アセットのインポートと設定
  • Chapter7-2:AndroidのKeystoreの作成

f:id:miki05:20200303091603p:plain f:id:miki05:20200302230528p:plain

こちらの試読版により、より多くの人に本書とその雰囲気を知ってもらえたらいいなと思っています。 ぜひ、お知り合いの方に広めていただけると幸いです。

Unity入門書の改訂版を書きました。

この度、Unityの入門書「Unity 3D/2Dゲーム開発実践入門 Unity 2019対応版」を執筆しました。 こちらは以前執筆した「Unity5 3D/2Dゲーム開発実践入門」の改訂版になります。 全国書店では本日2/20くらいから、アマゾンでは明日2/21に発売で、 ページ数やコラムは増量しましたが、お値段は据置でとてもお得です。

Unity 3D/2Dゲーム開発実践入門 Unity 2019対応版

Unity 3D/2Dゲーム開発実践入門 Unity 2019対応版

  • 作者:吉谷 幹人
  • 出版社/メーカー: ソシム
  • 発売日: 2020/02/21
  • メディア: 単行本

ということで、改訂を経た本書のおすすめポイント等を紹介したいと思います。

特徴1 :Unityの基礎知識に特化!体系的に学べる!

本書は、読者の方にUnityユーザーとして「ひとり立ち」してもらうことを目的にしています。 「ひとり立ち」とは、何か目標がある時に、 知っている知識をベースにいろいろ試してみたり、 適切なドキュメントを読みにいったり、コミュニティで質問したりして、 最終的には実現することが出来る状態です。 逆に「ひとり立ち」できていない状態というのは、 「何をしていいか・何から始めていいかわからない」状態ともいえます。

Unityは本当に素晴らしいゲームエンジンで機能も豊富なのですが、 それ故に覚える機能や操作がたくさんあるのも事実です。 また、ゲームというジャンルはRPG、アクション、パズル、2D、3D、VRなど、多岐に渡る技術や作り方が存在しています。 そのため、単に特定の機能やジャンルの作り方にフォーカスした説明では、 幅広い要件に対応出来る力が身につきにくいと考えています。

そこで、本書では出来る限りUnityやゲーム開発のコアとなる部分にトピックに絞り込み、 それらを、適切な広さと詳しさで体系的に説明することにしました。 C#の文法や、特定ジャンルのゲームロジックを細かく解説するよりも、 純粋なUntiyの知識の部分を450ページの中に「ギュッ」とつめこんであります。 それらも、これからUntiyと共に過ごす方(例えば自分でゲームを作ってリリースしたいとか、ゲームエンジニアとして働くとか) に必要だと思う機能を一覧化した後、ピックアップして構成を練っています。

全体の流れと紹介・利用機能を以下にざっくりまとめてみました。

f:id:miki05:20200220003720p:plain

また、発展的な内容や機能もコラムとして掲載しました。 これらのコラムでは詳しい利用方法までは紹介していませんが、 「こんな機能あるんだー」ぐらいにみてもらうことで、 いざ必要になった時のとっかかりにしてもらえたらと思っています。

特徴2:それっぽいゲームが作れる!

本書では、学習の途中で作成するサンプルゲームが「面白いこと」を重要視しました。 本書のコアコンテンツは4つのサンプルゲームをつくりながら、 Unityの機能や作法を学んでいくストーリーになっています。 4つのサンプルは、ほぼフルスクラッチで作成しますが(コードも全て誌面に掲載してあります)、 それなりにゲーム性があったり見栄えがよかったりします。 出来上がったゲームを自分のスマホに入れて、 他の人に遊んでもらいたくなる程度のものが仕上がります。

f:id:miki05:20200217003655p:plain

「面白い」を作るという、ゲーム開発はちょっと特殊な行為のように感じます。 言い方を変えると「面白い」と向き合う行為かと。 誰しもがゲーム開発をしていると「作っているこのゲームは面白いのだろうか?」と思うことがあるはずです。 それでも、開発を進めてリリースして、誰かに楽しんでもらうところまで漕ぎ釣られるのは、 「面白い」を作ることが「面白い」と感じるからだと思います。 そんな、ゲームを作るという面白さを体験してもらわなければ入門書として意味がない!という思いから、 サンプルのゲームは面白い・だけどちゃんとUnityの機能も学べるということを目指しました。

特徴3:ゼロからリリースまでアプリ開発事情をカバー!

本書のもう一つの特徴は、 スマートフォン向けの開発を全面的にカバーしているということです。 決してそれ以外のプラットフォームで参考にならないわけではないですが、 モバイルプラットフォームでリリースまでに必要なトピックをふんだんに取り入れています。

  • 実機環境構築
  • ゲームデザイン
  • インプット制御/加速度センサー
  • マルチアスペクト・解像度対応
  • リリース設定(アイコン・スプラッシュ・64bit対応)
  • 本番ビルド・ストア提出
  • セーフエリア対応
  • 動画広告の埋め込み

実際にリリースのことを考えると、 プラットフォームとの連携や事情を考慮しながら進める部分が結構あります。 これらは、あんまりまとまった情報としては無いように感じますし、 数年おきに新しい概念が登場したりしてキャッチアップが大変です。 Unityを利用すると、さっとスタンドアローン向けでexeやappをビルドすることができますが、 つまずいてしまう部分ってこういう泥臭いところだったりするんですよね。 本書は、そんな泥臭さの部分を代表的なプラットフォームかつ、 お手軽に試せるモバイルを例として、かなり実践的に扱っています。

特徴4:「これからも」Unityのスタンダードに対応!

本書はUnity2019.3をメインターゲットにしており、 比較的近年導入された「基本部分」に関わるトピックにも対応しています。

  • リリースサイクルとサプスクリプションモデル
  • Unity Hub
  • ネステッド・プレハブ
  • フラットデザイン・エディターUI

特に2018.3で導入されたネステッド・プレハブは、 全てのUnity上の作業を根本的に変化させる可能性を秘めており、 Unity2019.3でのエディターUIのデザイン変更も見た目が刷新されたインパクトある出来事でした。 本書は、数年おきに起きた全てのUnityユーザーが知るべき事柄にしっかりと追従していると言えます。

なお、タイトルには「Unity2019対応版」となっていますが、 おそらくUnity2020以降も問題なく利用できるはずです。 実は本書で紹介している物理エンジンやアニメーションなどの機能部分のトピックは、 前の版の時からあまり変更がありません。 これは、単に筆者がめんどくさくて変更しなかったわけではなく、 今も昔もUnityを使い始める上で必要な部分はそれほど違わないということだと言えます。

Unityでは、DOTSやHDRP、URP、シェーダーグラフ、Addressable Assets Systemなどなど、 どんどん新しい機能が追加されていますが、 それらはUnityの基本上に習得すべき事柄だと考えます。 本書では、単なるトレンドではなく、 今後もずっとUnityを利用していく上で最初に知るべきことに的を絞り取り上げてます。

こんな人におすすめ

以上のような特徴から、 ざっくり本書をおすすめしたい人は以下のような感じです。

  • 「Unityを触れる」から「Unityで作れる」という段階に実力を伸ばしたい人
  • これから業務でUnityを利用し始める人
  • 実際にゲームを開発してストア公開までを視野に入れている人

「プログラムに不慣れな方にはレベルが高いかも」という意見もいただいていますが、 すべての手順・コードを掲載・解説していますので、 写経を進めていけば問題なくサンプルを完成させられると思います。

f:id:miki05:20200220083728j:plain

執筆の苦労話とか

前の版「Unity5 3D/2Dゲーム開発実践入門」 は苦労した甲斐もあって、皆様からとても評価していただきました。ありがとうございます。 新卒の方から、学校の教科書でしたとか、知り合いの大手ゲーム企業で配布されたという話も聞きとても驚きました。

そういうことから、 本書の「しっかり体系的にUnityを学べる本」という立ち位置のようなものを自覚しました。 しかし2015年の発売からUnityやプラットフォームまわりの事情もだいぶ変わり、 情報がだいぶ古くなってしまったことに、ずっともやもやを感じていたのです。 そのような中で、2019年2月に本格的な改定の話をいただき作業を開始しました。

改定作業では、 最初に全体の修正内容を見繕いましたが、 サンプルゲーム自体を別ゲームには変更しないことにしました。 これは、 Unityを体系的に学ぶための機能を3章から6章にかけて重複なく利用し、 コード量を抑えながら面白いゲームにするという構造を、 緻密に設計した結果があの4つのサンプルだったからです。 ゲーム内容を変更して それらすべてのパズルを再度組み直すことはできなそうだなと...

とはいえ、サンプルゲームの方針やロジックはそのままでも、 アセットの見栄えを大幅にリファインし、 Unityの新機能などへの対応を果たし、 手順や説明もより分かりやすくなるように検討を重ねました。

そんなこんなで、 サンプルゲーム自体は変わっていないですが、 Unity新機能の検証や、紹介している機能の確認、 操作フローや説明自体のリファイン、 さらには2019年内で、どんどん更新されていくUnityの情報への対応などで、 丸々1年間かかったのでした。。。しんどかった

ただ、Unity Hubや2018.3のネステッドプレハブ、 2019.3のUIの刷新などの情報を含めて改定を実現できたのは、 とても良いタイミングだと思っています。

さて、本書最大のバージョンアップ点を最後に....

f:id:miki05:20200216190209p:plain

6章のアザラシの解像度が爆上がり!! ファミコン→プレステぐらいの進化はあるでしょう。

謝辞

サンプルのリファイン、カバー書き下ろしにご協力いただいたGaryuさん、いつもの事ながらありがとうございました。 また、担当のソシム木津様、締め切り間際等でも色々無茶なお願いを聞いてくださり、ありがとうございました。

そして、家事の負担とアザラシのイラストに協力してくれた妻に感謝。

ElectronとReactでAPI叩いて何か表示するアプリを試してみたメモ

先日、会社の業務外開発イベントに参加してきた。 これは、自分が新卒の頃からやっているイベントの後継で、 テーマ自由でもくもく作業するハッカソン、所謂もくもくそん。

今回は、ずっと昔から気になっていたElectronとReact.jsを使ってみることにした。 大半はJavaScript力を向上したいという思惑がある。

作るもの・使うもの

Redmine上の自分のタスクを、取得してきて表示するだけのアプリ。

ViewのフレームワークReact.jsを利用して、 自社の Redmine Rest APIのRestAPIを叩いて表示。 それらをElectronでアプリ化する。

Vue.jsとどっち試そうか迷ったが、 なんかいろいろ応用が効きそうなReact.jsにしてみることに。

Step0: nvm, node Install

まずnvmをいれる

$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.1/install.sh | bash

そして、とりあえずnodeの安定版いれる

$ nvm install --lts
$ nvm use --lts

Step1: Scaffold

React.jsのテンプレートプロジェクトをcreate-react-appでつくる

こちらの手順を参考させていただいた。 https://qiita.com/chibicode/items/8533dd72f1ebaeb4b614

create-react-appインストール

$ npm install -g create-react-app

プロジェクト生成

$ create-react-app redmine-desktop

できたプロジェクトはすでにgitリポジトリになってる。楽。

Step2: Electron化

こちらの手順を参考にさせていただいた。というよりほぼそのままの手順。

https://medium.com/@impaachu/how-to-build-a-react-based-electron-app-d0f27413f17f

以下パッケージを追加

$ npm install cross-env electron-is-dev

以下パッケージをdev環境に追加

$ npm install -D concurrently electron electron-builder wait-on

以下electron.jsをPublic以下に配置

const electron = require("electron");
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
const path = require("path");
const isDev = require("electron-is-dev");
let mainWindow;

function createWindow() {
  mainWindow = new BrowserWindow({ width: 320, height: 640 });
  mainWindow.loadURL(
    isDev
      ? "http://localhost:3000"
      : `file://${path.join(__dirname, "../build/index.html")}`
  );
  mainWindow.on("closed", () => (mainWindow = null));
}

app.on("ready", createWindow);
app.on("window-all-closed", () => {
  if (process.platform !== "darwin") {
    app.quit();
  }
});

app.on("activate", () => {
  if (mainWindow === null) {
    createWindow();
  }
});

以下をpackage.jsonに追加

...
"description": "",
"author": "Mikito Yoshiya",
"build": {
    "appId": "net.mikinya.redmine-desktop"
},
"main": "public/electron.js",
"homepage": "./",
...

package.jsonのscripts項目を以下に変更

...
"scripts": {
    "react-start": "react-scripts start",
    "react-build": "react-scripts build",
    "react-test": "react-scripts test --env=jsdom",
    "react-eject": "react-scripts eject",
    "electron-build": "electron-builder",
    "release": "yarn react-build && electron-builder --publish=always",
    "build": "yarn react-build && yarn electron-build",
    "start": "concurrently \"cross-env BROWSER=none yarn react-start\" \"wait-on http://localhost:3000 && electron .\""
},
...

この時点で

$ npm run start

でアプリが開発モードで起動するように

$ npm run build

でapp化してdist以下にappと配布用のdmgを出力できるようになった。

Step3: Presentation, React Component構築

ビューのレイヤーを修正

公式のチュートリアル等を参考にごにょごにょいじった。

CSSも適当にbootswatchのcss.minを入れた。

cssはただ配置してApp.jsからimportしただけだけど、これでいいのだろうか。

できたReactのコンポーネントは以下みたいな感じ。

import React from 'react';

class TaskCard extends React.Component {
  render() {
    return (
      <div className="card text-white bg-primary mb-3" >
        <div className="card-header">{this.props.title}</div>
      </div >
    );
  }
}

export default TaskCard;
import React from 'react';
import ReactDOM from 'react-dom';
import './bootstrap.min.css'
import TaskCard from './TaskCard'
import IssueUseCase from './useCase/IssueUseCase'

class App extends React.Component {
  constructor(props) {
    super(props);
    this.useCase = new IssueUseCase();
  }

  render() {
    this.useCase.getOwnIssues(issues => {
      var list = [];
      for (var i in issues) {
        list.push(<TaskCard key={issues[i].id} title={issues[i].subject} />);
      }
      ReactDOM.render(list, document.getElementById('issues'));
    });

    return (
      <div className="container">
        <div className="row">
          <div className="col-lg-12">
            <h2>Tasks</h2>
          </div>
        </div>
        <div className="row">
          <div className="col-lg-4">
            <div className="bs-component">
              <div id="issues"></div>
            </div>
          </div>
        </div>
      </div>
    );
  }
}

export default App;

この時点ではRestAPIからcurlで叩いたjsonをファイルで保存したデータをモックデータとして、Viewに表示してみる。記法やお作法の正しいやりかたは全然不明。

うん。これでとりあえずデモはできる。

f:id:miki05:20191113010021p:plain

Step4: DataStore, API実装

実際にAPIを叩いてサーバーのデータを取ってくるようにする。 通信と非同期の処理にaxiosをつかってみる。 XMLHttpRequstのラッパーでPromiseでイベントの制御ができるらしい。

$ npm install axios

通信部分はとりあえずトークンとかクエリとかベタがき。 あとでUI上から設定できるようにしよう...

import axiosbase from 'axios'

class RedmineApi {
  constructor() {
    this.axios = axiosbase.create({
      baseURL: 'https://url_to_redmine',
      headers: {
        'Content-Type': 'application/json',
        'X-Redmine-API-Key': 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
      },
      responseType: 'json',
    })
  }

  getIssues() {
    return this.axios
      .get('/issues.json?limit=100&tracker_id=4&status_id=1&assigned_to_id=270')
  }
}

export default RedmineApi;

ここで二つの問題がでた。 一つめはCORS(Cross-Origin Resource Sharing)で、異なるドメインへの通信を制限するJavaScriptフロントのよくあるやつ。 現状の開発状態でもlocalhostで立ち上げてるぽいし、うん確かにそうなるわな。 でもAppにバンドルした場合はどうなるんだ? これは、以下のElectron側の設定で解決できた。

electron.jsのnew BrowserWindow();のパラメータに以下を追加

...
  mainWindow = new BrowserWindow({
    width: 320, height: 640,
    webPreferences: {
      webSecurity: false
    }
  });
...

参考:https://qiita.com/yasuflatland-lf/items/4f57b6dd311d4918e8f5

もう一つは会社で運用しているRedmineが自己証明書で、ERR_CERT_AUTHORITY_INVALIDエラーがでて、 XMLHttpRequst系ではそれを無視できる設定にできなかったこと。 curlではkオプションを追加するだけだが。

こちらも同様に、以下のElectron側の設定で解決。 electron.jsに以下を追加

...
app.on('certificate-error', function (event, webContents, url, error, certificate, callback) {
  event.preventDefault();
  callback(true);
});
...

参考:https://qiita.com/yuya-oc/items/2764bf7a33c751498858

完成

とりあえず動くものができた。 APIトークン埋め込み、ユーザーID埋め込みなので、完全個人しか使えない。 全然時間足りなかった。

所感

  • Electreon便利, React良さそう
  • JSの作法もっと知りたい
  • webpackとかなんちゃらとか、いろいろ覚えることある
  • TypeScript覚えたい
  • Rxを導入してみたい
  • JSでテストどう書くんだ
  • Electreon上のプロジェクトでClearn Archtectureを適用してみたい
  • Appまでビルドして配布形式までとりあえず1日で走りきれたので満足
  • たまには違ったコンテキストの作業は刺激になる
  • 割と簡単に改良できそうなので、この後少しいじってみることにする

Unity Excel Importerをv1.1にバージョンアップ

ちょっと時間があったので、 去年作ったUnity上でエクセルをインポートするプラグインをアップデートした。

github.com

Release Note

  • SerializeFieldアトリビュートをサポート(非パブリックなフィールドでも利用可能に)
  • 空のセルを基本Default Valueとして扱う
  • Excel Assetのクラス名と実際のエクセルファイル名のひも付きをオプションで変更可能に
  • インポート時にログを出力するオプションを利用可能に
  • NameSpace付きのExcelAssetにも対応
  • インポートエラー時にシート名も表示

このプラグインは、 以下のUnityプログラミングバイブルのマスターデータ構築部分を執筆する際に作成したプラグインで、 結構丁寧に考えながら設計している(つもり)。

Unityゲーム プログラミング・バイブル

Unityゲーム プログラミング・バイブル

導入の仕方は以下 qiita.com

が、しかし、Unity Excel Importerでしらべると、 大御所テラシュールさんのExcel Importer Makerも候補に表示されググラビリティが低い。 Excel Importer Makerの紹介記事は結構でたりして少し寂しい。。。

そもそも、このプラグインを作った背景には、 いくつか自分の思う思想でエクセルのインポートを扱いたいという思いと、 書籍で紹介する上では、それらの機能に責任を持ちたいと思ったからだ。

もうちょい、いろんな人に使ってほしいので紹介する。

Unity Excel Importerの思想とかメリット

以下の三つが主な特徴だとおもう。

1. シンプル&高いポータビリティ

まず、一番重要視したのは、シンプルさ。メインのソースはExcelImporter.csのみ。 一部Editor上から導入をサポートするコードもあるが、そのあたりはなくても動く。 Editor拡張を利用しない場合は、数行のコードを自前で書けばよい。

ほぼEditor拡張を使わないようにしたことで、癖がなくどんな案件でも導入しやすいはず。 Unity Editorのメニューをほとんど汚すこともないし、冗長なコードが増えることもない。

また、Excel内のテーブルのスキーマは利用者がソースコードで定義する(Enityソース)。 これにより、以下二つのメリットがうまれる。

  1. jsonの様なシリアライズ形式にそのまま移行できる
  2. エンジニアはソースをいじるだけでいい(GUIをぽちぽちしなくてよい)

1.に関しては、結構重要。 プロジェクトの開発初期では、とりあえずエクセルでマスターデータを構築しておいて、 開発が進んだあと、サーバーから取得する形に変更するなど、 データのシリアライズ形式をスイッチするとめっちゃスムーズ。 つまり、プラグインのフローや形式になるべく依存せず、 プロジェクト内の都合を極力優先できるということ。

2.に関して、意外とエンジニアはGUIの手続きを操作するのが嫌いだったりする。 手順を間違えたり、既存のソースのコピペができなかったり、独自の自動生成フローが使えないから。

2. 必要スクリプトは自分でマネージできる

テラシュールさんのExcel Importer Makerはその名の通り、 ImporterをMakeするプラグインで、 エクセルごとにツールを使って専用のImporterを、専用の配置場所に自動生成する形になる。

反面、このプラグインは完全に「Excel Importer」でインポートロジックコードの追加生成はしないし、 スキーマを定義するソースの配置等は利用者側に委ねている。 (その代わりリフレクションをバリバリつかっているけど、RunTimeではインポート済みだから問題ない)

そのため、ちょっとしたデータ構造の変更とか、 フィールド名の変更とかも気軽にできるし、削除する際も気兼ねなくできる。

3. 実プロジェクトで培われたユースケースに準拠

実はこのプラグインのもとになったのは 2011年くらいにUnityを会社で使い始めたときに、 レベルデザインを簡単にするために作られたエクセルインポートスクリプトだった。

このスクリプトがめっちゃ便利で、 いろんなプロジェクトで秘伝のタレのように使われたり改修されてきた経緯がある。 つまり、実際のプロジェクトで運用に耐えうる実績を持つフローと言えると思う。

特にコメントアウトとかEnumの利用は結構重要だとおもう。

そして、プラグイン化した今も、 新しいプロジェクトのプロトタイプとかでも利用しているし、 データ層の仮実装として相当な開発速度向上に繋がっている(上記のとおり後でスイッチも可能)。

また、都度新しいユースケースも見つかったりして、 しばらくはちゃんと対応していく予定(今回v1.1)。

まとめ

つまり、実際の利用と運用を考えて頑張って設計したプラグインなので、 是非ともつかってみてほしいということを言いたい。

あと仕様はだいぶ出揃っているから、本当はテスト書きたい。

ちなみに宣伝になっちゃうけど、 このExcel Importerを使ってライトゲーム向けのマスターデータを構築する例を 上記のUnityプログラミングバイブルで紹介しているのでよければ参考にしてみてほしい。