backstage

合唱音源の新着情報の舞台裏

2018年1月のAzure VM メンテナンスは結局どうなったのか

3行まとめ

※2018年1月4日時点の情報

  • 任意のタイミングで再起動するセルフサービス期間は2017年12月28日 午前9時00分に開始し、2018年1月4日 8時30分に終了した
    • これは、開始日も終了日も当初の予定より約5日前倒しされた
  • 以降は予定メンテナンス期間となり、仮想マシンは順次自動で強制再起動されることになった

概要

2017年末から2018年始にかけて、Microsoft Azure 仮想マシン(AzureVM) の再起動が必要なメンテナンスが発表されました。 このメンテナンス期間が延びたり縮んだりして興味深かったので、どういう結果どうなったのかまとめておきます。

仮想マシン冗長化しておいて、再起動してもダウンタイムが無いような構成で組んでおくべきなのですが、なかなかそう理想ばかりで世の中は回りません。 私が個人で運用している合唱音源の新着情報.comは非商用だから良いものの、単一構成のWebサーバなのでVMを再起動されたタイミングでサービスダウンタイムが発生してしまいました。 このようなサーバを運用している場合、メンテナンスによっていつ再起動がかかるのかは重要な問題になります。

なお「セルフサービス期間」とは自由なタイミングで再起動をしてメンテナンスを終わらせることができる期間を指します。対して「予定メンテナンス期間」とは、強制的に再起動が発生する期間のことです。

時系列順の情報まとめ

[2017-12-20] 仮想マシンのメンテナンスとセルフサービス期間が発表

[告知] 2018 年 1 月 2 日より Azure IaaS 仮想マシンのメンテナンス期間が開始します – Japan Azure Technical Support Engineers' Blog (12月20日時点)より引用

2018 年 1 月 9 日から Azure プラットフォームのホスト メンテナンスが予定されており、これによってお客様の仮想マシンが再起動されます。 セルフ サービス期間の通知については、後日送付される正式な通知をご参照ください。現時点では、セルフサービス期間は 2018 年 1 月 2 日から 1 月 9 日となる予定です。

セルフサービス期間については未確定ですが2018年1月2日から1月9日までの予定と告知されました。 この時点で「1月9日まであるなら、正月明けの4日とか5日の営業開始後に対応すれば間に合うか」と判断した人もいたのではないでしょうか。

この当時の参考文献: Azure Virtual Machines (IaaS) の計画メンテナンス (来年1/2以降) (追記: 12/28以降に変更)satonaoki.wordpress.com

[2017-12-27] セルフサービス期間の延長が発表

[告知] 2018 年 1 月 2 日より Azure IaaS 仮想マシンのメンテナンス期間が開始します – Japan Azure Technical Support Engineers' Blog (12月27日追記時点)より引用

Azureデータセンターにてセルフサービス期間をなるべく長く用意させていただくべく、尽力させていただきました結果、セルフサービス期間は日本時間の12/28 午前 9 時より開始し、予定通り 1/9 午後 9:00 までを設けさせていただくこととなりました。

セルフサービス期間は 5日前倒しされて、 2017年12月28日 午前9時00分~2018年1月9日 午後9時00分になりました。 年始休暇が長い会社の場合も、年末ギリギリに対応できるようなスケジュールになりました。

なおメールでは翌日12月28日14時13分(つまりセルフサービス期間開始後)に「[お知らせ]: Azure プラットフォームにメンテナンスが予定されており仮想マシンに影響が生じます」というタイトルで届きました。 しかし1月10日から予定メンテナンスによる再起動が発生する事のみが記されており、セルフサービス期間に関する記述は説明はありませんでした。

この当時の参考文献: Azure Virtual Machines の計画メンテナンスbuchizo.wordpress.com

[2018-01-04] セルフサービス期間が急遽終了し、強制再起動を前倒し実施

CPU の脆弱性から Azure のお客様を保護するために – Japan Azure Technical Support Engineers' Blog より引用

2018 年 1 月 3 日 3:30 PM (太平洋標準時) すなわち 1 月 4 日 8:30 AM (日本時間)より、再起動が必要な仮想マシンは順次再起動を行ってメンテナンスを完了させてまいります。今回の更新の緊急性に伴い、本時刻をもって、一部のお客様でご利用可能となっていたセルフサービスのメンテナンス ウィンドウは終了となります。

ここで、今回のメンテナンスにはGoogle Security Blogに記載されているCPU脆弱性の対策が含まれることが公表されました。おそらく本件の緊急性の高さを踏まえて、セルフサービス期間が5日前倒しの1月4日に終了することになりました。

正確な時刻は不明ですが、このMicrosoftJapanのブログは1月4日未明にはすでに公開されていたようです。セルフサービス期間の終了まで残り数時間というギリギリのタイミングですが、一応これが事前の告知となりました。

一方メールでは「CPU 脆弱性対策の為にメンテナンスの実施を前倒し致します。」というタイトルで、本件を通知する1月4日14時16分に届いていました。 これはセルフサービス期間の終了後であり、私のサーバはすでに再起動が実施された後でした。 なおメールの内容はブログとほぼ同じでした。

この当時の参考文献: www.publickey1.jp

結論

  • Japan Azure Technical Support Engineers' Blog は早くて正確
    • メールでの通知よりもブログの方が早い
  • VirtualMachineは冗長化するべき
  • メンテナンス予定は変更されるかもしれないので、後回しにするべきではない
    • 早くメンテナンスをして、早く恩恵を受けられるようにするべき

2017年に買って良かったモノ7選+良かったゲーム7本

買って良かったモノ7選

ONKYO GRANBEAT DP-CMX1

www.jp.onkyo.com

Apple iPod Touchからの乗り換えです。アンプ2基+DAC2基を内蔵、128GBの本体ストレージに加えてmicro SDスロット。デュアルSIMですがmicro SDと競合しません。「ハイレゾ音源を好きなだけぶち込んでね」という気概の見える音楽特化マシンです。 DAPにSIMが刺さるようになっただけのようなスペックですがカテゴリーは一応Androidスマホであり、通話はもちろんYouTubeSpotifyで音楽を聴いたりもできる点はDAPには無い長所です。

iPod touch(約80g)から乗り換えたので、234gという重さは気になります。

Sony MDR-NC750

www.sonymobile.co.jp

DP-CMX1に合わせて買ったノイズキャンセリングイヤホン。SonyのMDR-NCシリーズはかれこれ10年ぐらい使い続けてますが、本製品も安定の性能。DP-CMX1のアンプも癖の無い性能なので、余計な味付けの無いMDRシリーズとは相性が良いと思います。

DP-CMX1は2.5㎜バランス接続端子搭載なので、せっかくなのでPioneer SE-CH5BLも買いましたが、音質は好みなものの遮音性が無さすぎてダメでした。やはり私はノイズキャンセリングが無いと生きていけない体のようです。

Trinity NuAns NEO

NEO Top | NuAns NEO

マウスコンピュータ MADOSMA Q501からの乗り換え。NFCとUSB Type-C対応のWindows 10 Mobile。相変わらず高いバッテリー効率のお陰で充電を2,3日忘れても戦える、通話+テザリング中心の端末として活躍中です。

Windows Mobileは将来性が無いのが悲しいです。NuAnsシリーズも2017年モデルはAndroid機となっています。

Microsoft Surface Book 1 with Performance Base

f:id:s2terminal:20171231201328j:plain

画像は https://www.microsoft.com/ja-jp/surface/devices/surface-book/overview より引用

Surface Bookは2台目。Core i7 + 16GB RAMモデルです。買った翌月に2が発売されて投げ売りされ始めた悲しいモデルですが、ハイスペック・大容量バッテリー・タッチパネル搭載のハイエンドWindows PCとして現役バリバリです。 今年は本機を何度か勉強会やLTに持っていきましたが、高性能タッチペンPowerPointでのプレゼンと相性が良かったです。ただ決して軽くは無いのでモバイル中心の用途はやや厳しいです。

eyemirror 魔法少女まどか☆マギカ[新編]叛逆の物語 コラボ眼鏡 SAYAKAモデル

eyemirror.jp

いままでは格安のメガネしか買ったことなかったのですが、ガタが来ていたのもあり今回このタイミングで買い替えました。思い切ってレンズとフレーム代金を合わせて今までの8倍ぐらい値段するモデルに。

f:id:s2terminal:20171231211242p:plain

描き下ろしのイラストがかわいいです。付属の眼鏡吹きはマウスパッドにはさんで使っています。

HOMURAモデルが劇中の三つ編みのときの使い回しではなく新編のモデルで書き下ろされているのは、私としては好印象ですが賛否の別れるポイントでしょうか。レンズを入れに行ったメガネスーパーの店員さんは「お客様(SAYAKA)とMADOKA、KYOKOは来たけど、MAMIさんモデルのあのフレームを一度見てみたい」と繰り返しつぶやいていました。

ASUS Chromebook Flip C101PA

www.asus.com

ChromebookとしてはAcer CB3-111からの乗り換えです。CB3-111以上に小型軽量で、タッチパネル搭載でAndroidアプリが動く長所を持ちます。 が、いざ使ってみると、意外とAndroidアプリ使わない事に気づきます。Secure ShellさえあればChromeでだいたいの事はなんとかなります。

ふとんタナカ じぶんまくらレギュラー

jibunmakura.com

ビックカメラで買った500円の枕から買い替えました。今年買って最も後悔している物です。コレを買ったせいで家にいるあいだ無限に寝てしまい、開発とかスプラトゥーンとかやる時間が全然無くなってしまいました。来年はマットレス欲しい。


2017年に買ってよかったゲーム7選

[Switch] ゼルダの伝説 ブレス オブ ザ ワイルド

閉鎖されたフィールドをアイテムで徐々に切り開いていく人気シリーズ「ゼルダの伝説」従来の特徴を粉々にぶち壊し、今までとはまったく異なる、自由に攻略できる「Open Air」として見事に再構築した傑作。本作については数多くのレビューがありますが、最も的を得てるなと思ったのがこちら。

news.denfaminicogamer.jp

基本的に情報を外に出さない任天堂が、CEDECで大々的にセッションを開いたことでも話題になりました。「お前たちに本物のゲームの作り方を教えてやる」とでも言わんとするセッションの数々は、ゲーム開発者ではない私の耳にも噂が入るほど話題になっておりました。京都に本丸を構えるゲーム開発の秘密結社たる任天堂の威厳を見せつけられることになりました。

www.4gamer.net

なお2度の大型追加コンテンツがあった今もなおサウンドトラックが発売されていないというバグが修正されていないので、開発メンバーは反省して頂きたい。

[3DS] モンスターハンター ダブルクロス

www.capcom.co.jp

いつも通りのモンスターハンターに、スタイルと狩技を追加して新しい感覚を盛り込んだ作品です。モンハンは基本的にやる事はいつも変わらないので毎回はプレイしないのですが、こうして数年に1度やりたくなります。

来年はモンスターハンター:ワールドが発売されますが、果たして。

[Switch] ヒューマンリソースマシーン

ec.nintendo.com

プログラミングをゲームにしたというので知育的な内容かと思いきや、足し算とループで掛け算を実装するところから始まり、終盤は素因数分解やソートアルゴリズムと、かなり本格的な内容になります。デバッグ機能もちゃんとしており、おもちゃではないホンモノのプログラミングをパズルゲームとして昇華させています。 一応プログラムで飯を食っている私ですが、途中で心が折れました。

[Switch] スプラトゥーン2

www.nintendo.co.jp

WiiUで大きな話題となった対戦アクションシューティングの続編です。基本的には前作の延長線上であり、ゲームバランスの変化、新ブキ追加、新ステージ追加など、アペンドディスク的な立ち位置です。Switchになったため持ち運んで遊べるというのが、本作最大の長所です。

[PS4] NieR:Automata

www.jp.square-enix.com

見た目はただの格好良いSFアクションシューティング。ですが、進めるほど明らかになる予測不可能なストーリーや、衝撃的な演出の数々は唯一無二です。グラフィックのクオリティはPS4作品の中でも突出して高いわけではないものの、その退廃的な情景の美しさと、ゲームらしからぬ落ち着いた色使いのUIデザインの調和には目を奪われます。

www.platinumgames.co.jp

[PS4] ドラゴンクエスト11 過ぎ去りし時を求めて

www.dq11.jp

過去作品、特にドラゴンクエスト8以前を強く意識した昔ながらのドラクエ。スキルパネルなど若干現代的な要素も取り入れつつも、バトルもシナリオも伝統を守った丁寧な作りのおかげで、最新作でありながらも昔懐かしい気持ちにさせてくれます。シリアスな展開もギャグ要素もPS4のハイクオリティなグラフィックで表現され、その演出が面白かったりします。

[Switch] ゼノブレイド2

www.nintendo.co.jp

コテコテの王道JRPG。前作を意識したような展開や演出は目立つものの、直接的なつながりが示されるシーンは片手で数えるほどしかありません。少年漫画のような熱いシナリオは、前作ゼノブレイドから正統進化した完全新作として楽しむことができました。

不親切なUI、複雑怪奇なコンボシステムなど、プレイアビリティの低さは相変わらず。前作またはゼノブレイドクロスをやっている前提と思われる、システムの説明不足な箇所が多く見受けられます。しかしテクスチャを貼る前に操作可能になるというぶっ飛んだ仕様のお陰でファストトラベルのロード時間が異様に短く、スムーズな冒険に一役買っています。 「UIが分からなくてもゴリ押しでUXは向上できる」 という、良い方向にも悪い方向にも大変男らしい作品でした。

なお本作もサウンドトラックが発売されていないというバグがあるので、早急なリリースを待っています。

PHPカンファレンス2017でレガシーシステム対応の話を聞いてきた

※1週間経って資料が多数追加されたので、記事を半分くらい加筆修正しました

f:id:s2terminal:20171008122237j:plain:w300

PHPカンファレンス2017に行ってきました。

phpcon.php.gr.jp

聞いてきたセッション

今回は レガシーなシステムといかに向き合うか をテーマにセッションを選んできました。 なので、選んだのはすべて事例発表セッションです。

似たような題材のセッションを6つも選んだ都合上、近い話が多かったので、どんな話があったのか以下に簡単にまとめてみます。

レガシーなシステムがあると何が悪いのか?

  • セキュリティ が担保されない
  • アプリケーションの パフォーマンス の向上に限界
  • 新しい機能が使えず 生産性 が上がらない
  • 開発に関する 情報収集 が困難になる
  • 技術者が集まらず 採用不利

などなど、数あるデメリットを差し引いても、レガシーコードは残り続けます。 直接的に利益や価値を生み続けているからです。

ならば私たちにできるのは、「レガシーシステムをメンテナンスし続ける」か、それとも「新しい環境に移管する」かの2択になります。

VOYAGEさんのセッションのフレーズを借りると 「コードを自分たちの手に取り戻す」 事です。

コードを自分たちの手に取り戻す

レガシーなコードとは、何を足したら壊れるか分からない、何を引いても壊れるか分からない、 ジェンガ のようなものだと、VOYAGEさんのセッションでは喩えられていました。

  • ソースコードの全体像を誰も把握しておらず、読みづらい
  • 使われていないと思う箇所があるが、消す勇気が無い
  • エラーログがたくさん出ているが、だれも見ていない
  • 開発環境構築方法が確立されていない。たとえば、ひとつの大きなサーバにみんなでsshして開発している
  • KPI改善・機能追加のタスクが常に最優先で依頼されるため、リファクタリングなど品質担保に割く工数が無い
  • テストコードは無いか、メンテされていない
  • 前任者は退職しておりコードの意図は分からない
  • 不具合があるまま長らく放置され、それが仕様になってしまっており修正できない
  • そんなよく分からないシステムだが 動いており、利益を生み出し続けている

弁護士ドットコムさんのセッションの言葉を借りると カウボーイスタイルの開発 です。

プロジェクトのステージによって、考えるべきものは異なってきます。 明日には撤退するかもしれないようなシード期であれば、いかにサービスを良くするか?だけに注力するべきです。

そこから事業が成長するにつれて、後回しにしてきたソースコードの品質、サービスのスケーラビリティ、タスクの優先順位のようなプロジェクトマネジメントの重要性が上がっていきます。 こうなっていくと、 レガシーコードの対処 も必要なフェーズになってくるわけです。

https://image.slidesharecdn.com/20160901awsstartupsecuritytalkshkiriyam-160912001259/95/aws-startup-security-talks-aws-7-638.jpg?cb=1481444401

レガシーコードと付き合っていくために必要な事の例としては

  • レガシーコードを減らす
    • 適切な処理共通化や、地道なgrep等で、不要なコードをできるだけ削除していく
    • Vagrant,Chef,Ansible,Docker等で、開発環境構築を容易にし、ローカル開発可能にする
    • チーム全員にPhpStormを導入して静的コード分析することで、内容の把握できないレガシーコードを極力減らす
    • Redashを入れることで、不要になった管理機能をどんどん削除していく
  • これ以上レガシーコードが増えないようにする
    • git運用フローを決め、コードレビューをルール化する
    • コーディングガイドラインを制定し、ペアプロで浸透させ、チームで生産するコードの品質を向上する
    • スクラムを導入し、適切な優先度判断ができる開発スタイルを確立する

などが挙げられていました。

新しいシステムに移行する

一方で、PHP5系→7系のように、新しいシステムに移行した話も多く聞いてきました。

  • 継続的テスト環境を用意する
    • 簡易でもいいのでE2Eテストを
    • fluentd等でエラーログを収集しリアルタイムで通知できるように
  • リソース(人員、工数)を確保する
    • アプリ担当とインフラ担当の数名で、数か月以上かけて、というチームが多かった印象
    • QAチームがいない場合はチーム全員で検証するための時間を確保しよう、という話も
    • アーリーな事業フェーズではKPI改善や機能追加優先。サービスが成熟して安定黒字を出すようになったら移管の話を
    • パフォーマンス改善などユーザーメリットや、サーバー費用削減のような、具体的なメリットを打ち出す
  • 諦める事を決める
    • レスポンス改善は目指さない、デザインは変えない、deprecated警告は対応しない、など
    • これをしないと、やることが増え続けて何年経っても終わらなくなってしまう
  • 移行する順番を決める
    • HTTPエンドポイント単位やマイクロサービス単位などに分割して、少しずつ移行する。システムすべてを一気に移行することは難しい。
    • 簡単なもの、影響度の少ない部分、行数の少ない箇所から順番に進める
    • パスによってサーバごと切り分ける等で、新旧の両バージョンを同居させる

また、New Relicでアプリケーションをモニタリング するとか、後方互換性を維持し、新旧両方のPHPバージョンで動くようにして同じテストを通す とかは複数の事例で言及されていたので、鉄板の手法のようです。

こういったPHPバージョンアップやレガシーコードとの付き合い方のようなセッションが多く、どのセッションもとても人が集まっていました。 会議室にとても入りきらないので急遽サテライト会場が用意されたり、話を聞いている人たちの反応が「あるある~」といった感じだったりして、レガシーシステム対応」を課題に思っている人はとても多いのを実感しました。

その他のセッションの資料等については、TECH PLAYレバテックさんのブログにまとまっています。

聞くことができなかったセッションの中では Docker 系の話が多かった印象です。「レガシーなシステムと向き合うために、開発環境を整えよう」という文脈でも、Dockerが話題に上がったセッションもありました。

その他雑記

PHPカンファレンスはネットが快適でいつも助かっています。

あと、昨年と違って今年はお弁当の販売は無かったようで、昼休憩でちょっと路頭に迷いました。

s2terminal.hatenablog.com

今年は懇親会には行かなかったのですが、懇親会LTには当日申し込み枠が設けられており、すべて埋まっているようでした。

参考文献

【memo】WindowsでPackageManagerを使う

自分用メモ

まずはPowerShellを管理者権限で立ち上げ、スクリプトの実行許可をつけておきます。

PS > Set-ExecutionPolicy RemoteSigned
PS > Get-ExecutionPolicy
RemoteSigned

続いて一般権限でPowerShellを立ち上げなおし、Chocolateyから必要な物を持ってきます。

PS > Get-PackageProvider Chocolatey,PowerShellGet -ForceBootstrap
PS > find-package    git, virtualbox, paint.net, github, mysql.workbench, winscp, vagrant, google-chrome-x64, 7zip, slack
PS > install-package git, virtualbox, paint.net, github, mysql.workbench, winscp, vagrant, google-chrome-x64, 7zip, slack -providername chocolatey

以上です。

これで正常終了したのですが、なぜかVirtualBox,WinSCP,7zipは上手くインストールされていないようでした。 調べてもよく分からなかったので諦めました。

もし他に必要なものがあるかどうか調べるならば、PS > find package | moreとかで確認できると思います。すごい時間かかりますが。

参考

dev.classmethod.jp

rcmdnk.com

kanonji.info

【Azure Cognitive Services】画像認識でalt属性の説明文を自動生成してみた

引越して1ヶ月半、ようやく家にネットが通ったので何かコードを書こうと思いました。

Microsoft Azure Cognitive Servicesには便利そうなたくさんAPIがあります。 そのうちComputer Vision APIを使うと、画像を解析して説明文などを自動生成できます。

参考:過去の記事 s2terminal.hatenablog.com

Computer Vision APIが吐き出す情報は英語か中国語です。 今回はさらにこれをTranslator Text APIで日本語化し、imgタグにして吐き出すプログラムを書いてみました。

f:id:s2terminal:20170814035609p:plain:w360

Public Domain Picturesから適当にいくつか画像を取ってきて、説明文を付けてもらいました。

「木からぶら下がって緑のバナナの束」

木からぶら下がって緑のバナナの束

<img alt="木からぶら下がって緑のバナナの束" src="http://www.publicdomainpictures.net/pictures/130000/velka/banana-bunch-1442837481wI7.jpg#.WZCXAvp82Mc.link">

画像のURLを入力するだけで、こういったalt属性のテキストを自動で書いてくれます。 精度はなかなか良い感じです。

「フェンスの横にゼブラ立って」

フェンスの横にゼブラ立って

<img alt="フェンスの横にゼブラ立って" src="http://www.publicdomainpictures.net/pictures/230000/velka/zebra-at-groenkloof-picnic-spot.jpg#.WZCX2R_ZqTY.link">

フランス料理の添え物みたいな言い回しが気になりますが、内容は完璧です。

「白砂のビーチに立っている人」

白砂のビーチに立っている人

<img alt="白砂のビーチに立っている人" src="http://www.publicdomainpictures.net/pictures/30000/velka/drink-on-beach.jpg#.WZCRVmnOXuE.link">

心霊写真でしょうか。

実装

ReactTypeScriptwebpackという、ほとんど私に馴染みのない技術の組み合わせで作りました。よく調べもせずノリで技術選定したので、生産性の低さが半端無いです。

こんな感じで環境が用意できます。準備は簡単です。

$ echo "{}" > package.json
$ npm install --save-dev webpack typescript awesome-typescript-loader source-map-loader
$ npm install --save react react-dom @types/react @types/react-dom
$ npm install --save superagent @types/superagent

実装時間の8割は、ReactでAPIキーみたいなセキュアな設定情報をどこにどう書けば良いのか悩んでいました。

残りの2割はドラゴンクエスト11でマジスロを回しながらコードを書いたので我ながらかなり適当です。はぐれメタルヘルムがもう1個欲しいので仕方ないです。

メイン処理になるmain.tsxはこんな感じです。

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import * as SuperAgent from 'superagent';
import * as config from './config';

interface ImageFormProps {
}
interface ImageFormState {
  image_src: string;
  textarea_value: string;
  header: string;
}

class ImageForm extends React.Component<ImageFormProps, ImageFormState> {
  constructor(props) {
    super(props);
    this.state = { image_src: '', textarea_value: '', header: '画像のURLを入力して下さい' };
    this.handleChangeURL = this.handleChangeURL.bind(this);
  }
  handleChangeURL(event) {
    var image_url = event.target.value;
    this.setState({image_src: image_url,header: "(解析しています...)"});
    SuperAgent
      .post(config.computer_vision.api_url)
      .set('Ocp-Apim-Subscription-Key', config.computer_vision.api_key)
      .set('Content-Type', 'application/json')
      .send({url:image_url})
      .end(function(error, response){
        if (error) { return this.setState({header: response.text}); }
        var desc = JSON.parse(response.text).description.captions[0].text;

        this.setState({header: `(翻訳APIのアクセストークンを取得しています...)`});
        SuperAgent
          .post(config.translator_text.issue_token_url)
          .set('Content-Type', 'application/json')
          .set('Accept', 'application/jwt')
          .set('Ocp-Apim-Subscription-Key', config.translator_text.api_key)
          .send()
          .end(function(error, response_token){
            if (error) { return this.setState({header: response_token.text}); }
            var token = response_token.text;
            this.setState({header: `(「${desc}」を翻訳しています...)`});

            SuperAgent
              .get(config.translator_text.api_url)
              .query({
                'appid': 'Bearer ' + token,
                'text': desc,
                'to': 'ja',})
              .set('Accept', 'application/xml')
              .end(function(error, response_trans){
                if (error) { return this.setState({textarea_value: response_trans.text}); }
                var parser = new DOMParser();
                desc = parser.parseFromString(response_trans.text, 'text/xml').firstElementChild.textContent;

                this.setState({header: desc, textarea_value: `<img alt="${desc}" src="${image_url}">`});
              }.bind(this));
          }.bind(this));
      }.bind(this));
  }
  render() {
    return (
      <div>
        <h1>{this.state.header}</h1>
        <form>
          <input
            type="url" placeholder="http://www.example.com/" size={40}
            onBlur={this.handleChangeURL}
          />
        </form>
        <textarea
          placeholder="ここにimgタグが出力されます" rows={5} cols={40}
          value={this.state.textarea_value}
        />
        <img src={this.state.image_src} width="100%" />
      </div>
    );
  }
}

ReactDOM.render(<ImageForm />, document.querySelector('#app'));

handleChangeURL()のコールバックをみると残念な気持ちになってきます。 納品用コードはちゃんとPromiseか何か使ってきれいに書いたほうが良いと思います。

ソースコードの全文はGitHubに上げました。

github.com

まとめ

これくらいなら人間の手で説明文を書いたほうが早いと思いました。

参考文献