Dance with Tech

プログラミングとか学んだことの備忘録ブログです。

レガシーシステムをリプレイスして古の遺産を浄化した話

まえがき

タイトルの通り、少し前に 8 年近く(正確な歴史は不明)動いていたシステムをリプレイスしました。

かかった期間は約 2 年、発行した課題チケット数は 6000 超え、リリース直前に直属上司が退職など紆余曲折ありました。

良かった点や反省点が多くあったので、記憶が新しいうちにアウトプットしようと思います。

なぜリプレイスするのか

単純にエンジニアが「レガシーだからモダンな環境にリプレイスしたい」と言っても、事業責任者や経営層にメリットを理解してもらえないと実施できません。

今回は後述する問題によって、事業の足を引っ張っているという結論が出たためリプレイスに至ったと認識しています。

セキュリティの問題

システムの問題

  • フレームワークのコア部分を魔改造
  • 一度リプレイスしようとして失敗した昔の残骸(Python のコード)が残っている
  • テストコードがない
  • バージョン管理が Subversion
  • 密結合
  • 1 つのリポジトリを別部署の別サービスと共有している
  • サービスA のバリデーション定義を変更したら、サービスB のバリデーション定義も変更されてしまう
  • エラーに気づけない(ユーザーからの問い合わせで初めて気づくなど)
  • サイトが http

DBの問題

  • 1 テーブルのカラムが大量に存在する
  • 使用していないテーブルが混ざっている
  • 何でも DB で管理しようとしているためデータが複雑化している(〇〇カテゴリーのネスト構造をマスターとして管理など)
  • スロークエリ多数
  • 命名に一貫性がない
  • ***_table2 が存在する
  • m_***_table のようにマスターテーブルを想起させるプレフィックスが付いていたりするが、実際はマスターではなく頻繁に更新される普通のテーブルだったりする

事業的な問題

  • 上述の理由によりデリバリーのスピードが出せず、施策が実行できない(時代の変化についていけない)
  • テストが人力のみなのでシステムのクオリティが担保できない
  • 枯れた技術を使用しているため、エンジニア採用時の足かせになる(または退職される)

どうリプレイスしたか

ここは書こうと思えばいくらでも具体的にかけますが、キリがないのでざっくりポイントだけ書きます。

システム構成

  • オンプレからクラウドAWS)に移行
  • マイクロサービスアーキテクチャ導入
  • Frontend ⇔ API GatewayAPI
  • API 実装時はテストコード必須に
  • PHP は 7 系にアップデートし、フレームワークは Laravel に変更
  • MySQL は 5.7 互換の Aurora に変更
  • DB は全て再設計し、新テーブル用にデータをコンバート
  • 画像系と静的コンテンツは S3 で管理
  • インフラ周りは Terraform と Ansible で管理
  • フロントエンドは Vue や React で作成

開発方法

  • 2 週間ごとにスプリントを切って回していくスクラムを導入
  • 課題の管理や進捗の把握は JIRA で統一
  • 1 人でフロントエンドからバックエンドまでを担当
  • システムとしてどうあるべきかということを先に提案し、なるべく既存システムに近づけてひたすら機能を開発していく

体制

開始時

  • エンジニア: 2 名
  • プロダクトオーナー(直属上司) 1 名
  • 部長: 1 名

終了時

  • エンジニア: 5 名
  • 部長: 1 名

やらなかったこと

  • デザインのリプレイス(リニューアル)
    • 単純にデザイナーがいなかったというのと、システムに比べてスタイルガイドなどはかなり丁寧に作られていたのでデザインは踏襲することにしました
    • ただ、純粋なコーディング部分は Webpack で管理できるように書き換えました

リプレイスするにあたり追い風だったこと

  • リリース当日はサイト停止 OK
  • 廃止できる機能が多かった

大変だったこと

旧システムの有識者が 0 の状態からのリプレイス

プロジェクトにアサイン後、唯一の有識者だった派遣社員エンジニアが退職してしまい、手を動かすエンジニアがアサインされたばかりの自分と、入社したばかりの業務委託の方のみになってしまいました。

そのため、かなり手探りの状態からリプレイスプロジェクトが始まり、スタートダッシュができませんでした。

データの移行

データを移行するためにデータコンバーターを作成しました。

「旧DBからデータ取得→バリデーション→新DB用にデータを加工→新DBにインサート」という流れです。

移行するテーブル 1 つひとつに、このロジックとテストコードを作成しなくてはいけないため、かなり時間を費やしました。

また、データの移行を失敗すると取り返しがつかないことが多いので、かなり慎重に行う必要がありました。

パスワードの移行

可逆だったパスワードを不可逆の値にするために一旦復号化する必要がありました。

旧パスワードが pear の Crypt_Blowfish を使用していたため、composer に pear のライブラリを追加しました。。

そして、そのままでは PHP 7 系では動かないので、/pear-pear.php.net/Crypt_Blowfish/Crypt/Blowfish.php を改修することに。。

※ そのときの調査ログ

工夫したこと

フロントエンドはなるべくサーバーレスに

EC2 インスタンスは結構料金がかかるので、可能な限り SPA で構築することにしました。

SEO 対策が必要なサービスは SSR できる Next と Nuxt を導入して対応しました。

反省点

SEO の影響をなめていた

そこまで SEO に依存していないコンテンツでしたが、それでも目に見えて集客力が下がったため、もう少し真剣に考慮するべきだったと思います。

ちなみに SPA にした影響というよりは、旧 URL からのリダイレクトやエラーページのステータスコード、ページ構成などが主な理由です。

サービス間の連携テストの実施が遅かった

これはマイクロサービスならではですが、各サービス間をまたいだテストをするのが少し遅かったです。

連携テストをして初めてログイン周りの不具合などが見つかりました。

そして、結果的にリリース日を 2 週間ずらすことになってしまいました。。

サービスが属人化してしまった

スピードを重視していたため、1 人 1 サービス(場合によっては複数)を実装してもらうことにしたのですが、そのサービスについて詳しい人物が限定されてしまいリスクを生んでしまいました。

ある程度はスピードとのトレードオフなので仕方ないかもですが、もう少し横断的に開発していくべきだったなと思っています。

ただ、メンバー全員が責任を持って取り組んでくれたおかげで、誰もメンバーが欠けることなくリプレイスを終えることができました。

あとがき

0 → 1 というより、マイナス → 0 にするフェーズだったのでかなり貴重な経験をさせてもらいました。

エンジニアとしても成長できました。

事業責任者と関わることも多かったので、浮かび上がる課題に対してエンジニアリング以外で解決する方法を学べました。

また、エンジニアという役割上、課題をどう解決していくかという How に目が行きがちですが、そもそも課題や目的は何なのか、はたまたそれは本当に課題なのかという Why の視点を持てるようになったことが良かったです。

おまけ

新旧リプレイス表

環境
全体構成 モノリシック マイクロサービス
サーバー オンプレ クラウド(AWS)
インフラ構成管理 手動 Terraform, Ansible
バックエンド言語 PHP 5.1 PHP 7.1
バックエンドフレームワーク Ethna Laravel
フロントエンド jQurey Vue, React
DB MySQL 5.5 MySQL 5.7(Aurora)
バージョン管理 Subversion Github
メール オンプレ SendGrid API

Django(Python)のDB操作まとめ

仕事でDjangoPython)に触る機会があり、0から学習しながら進めています。

今回は個人的に分かりづらかった、DB(SQL)周りの内容をまとめました。

ドキュメントを読んでも分かりますが、ちょっと読みづらいです

 

条件指定

SQLで条件を指定したい場合は「filter」を使えばできます。

誤解を恐れないで言うと、

filter = where

という認識で良いと思います。

 

サンプル

 

複雑な条件を使いたいときは Q object を使う

 

日付型のインサートとアップデート

ちょっとSQLとズレますが、Model で以下のように設定すると、良しなにやってくれます。

 

・auto_now_add=True にすると自動で今の時間がインサートされます

createdt = models.DateTimeField(auto_now_add=True)

 

・auto_now=True にすると自動でインサートされるしアップデートもされます

update_dt = models.DateTimeField(auto_now=True)

 

※参考先↓


 

Swiftでランダムな文字列を生成する方法

Xcodeのバージョン:7.1

Swiftのバージョン:2.1

 

方法

ランダムな数値を生成した後、

その数値の場所の文字列を取得すれば、

おのずとランダムな文字列が生成できます。

 

Swift 2以降は、

advancedBy(n)

を使って任意の場所の文字列を取得できます。

 

 

注意点

上述した通り、

letter[letter.startIndex.advancedBy(randNum)]

のように、

文字列の変数[]

で囲まないと正常に動作しませんでした。

具体的に言うと、advancedBy(n) の「n」に入った数値をそのまま出力してしまいました。

 

何か僕がミスってるのかもしれないですが、

同じような状況に陥った方は上記の方法を試してみてください。

 

詳解 Swift 改訂版

詳解 Swift 改訂版

 

Swiftでキャリア情報とかOS情報とかデバイス名とかIPアドレスとか取得する方法

Xcodeのバージョン:7.1

Swiftのバージョン:2.1

 

ユーザーが使用している端末のデータを取得したいときがあります。

キャリア名とかOSのバージョンとかデバイス名とか。。

ある程度の情報は、以下の方法で簡単に取得できます。

 

IPアドレスだけ特殊で、

Bridging Header(ブリッジングヘッダー)を使わなければ取得できないようです。

ブリッジングヘッダー作成の方法はこちらを参考にしました。

追加したブリッジングヘッダー(.hファイル)に

#include <ifaddrs.h> 

を追加後、

で取得できます。

 

ちなみに、フレームワークプロジェクト(Cocoa Touch framework)だと、

ブリッジングヘッダーは使えないそうです。。

 

詳解 Swift 改訂版

詳解 Swift 改訂版

 

iOSアプリ(9対応)のリリース準備・対応で苦労したこと5つとおまけ

リリースというものは、そう何回もやるもんじゃないので方法を忘れがちです。

覚えている今のうちにメモしておきます。

※ちなみにXcode7を使っています。

f:id:kmatz90:20151108195807j:plain

 

1.リリースするための事前準備が意外と多かった

  • DistributionタイプのCertificateが必要
  • App IDが必要

※ここで出てくるBudle IDとXcode上のBundle Identifierがイコールじゃないとリリースできません

  • DistributionタイプのProvisioning Profileが必要

方法はこちらが参考になりました。

 

2. 1度iTunes ConnectにBuildしたらBuildの値を上げないと再Buildできない

アプリをリリースするにはiTunes ConnectにXcodeからBuildする必要があります。

※方法はこちらを参照。

しかし、Buildし終わってから、

「やっぱりあそこはこうしよう!」って思い立って修正したくなります。

きっとなります。ほぼなります。必ずなります。

その際はXcodeから、

「General」にある「Build」を「1.0.1」のように上げる必要があります。

そうすれば別のBuildとみなしてくれて再度Buildできます。

ちなみにリリース後にアップデートするときは「Version」を上げます。

 

3.スクリーンショットAppleの画像などがあると商標違反でリジェクトされる

アプリ申請時には、

アプリの見せ場的なものを載せたスクリーンショットを、

一緒にアップすることになるんですが、

そこにAppleの商標情報があるとリジェクトされます。

今回のアプリは見せ場的なシーンが少なかったので、

作ったアプリのアイコンが写っているホーム画面のキャプチャをアップしたら、

Apple製品のアイコンも載ってしまい怒られましたw

 

4. 「広告表示してないのにAdvertising Identifier使ってるよ」ってリジェクトされた

Advertising Identifier but does not include ad functionality...

「Advertising Identifier」っていうのは広告識別子のことです。

広告タグとかリンクコードの認識で大丈夫だと思います。

iADとか使ってないし、心当たりがなかったのですが、

nend、i-Mobile、Adstir?とかは裏で用意してるだけでも引っかかるようです。

※文字列だけでも引っかかりました

これ地味に引っかかる人いるんじゃないですかね?

 

5. リリース後のApp Storeのリンク作成

通常、PCのiTunesApp Store)からiOSアプリを探そうとすると結構苦労します。

(というかできるのか?)

そんなときは「Link Maker」を使うと簡単に辿り付けますし、URLも発行できます。

検索するときの注意点として、日本の場合は「Store Country」を「Japan」にし、

iOSアプリの場合は「Media Type」を「iOS Apps」に変更する必要があります。

 

おまけ

実はApp Storeの審査は特急で行うように申請ができます。

※方法はこちらを参照

試しに「Android版」が既にリリースされているので、

早く審査してくれって申請してみたところ、

案の定、却下されましたww

通常はクリティカルなバグの修正や、

ハロウィンなどのイベントに合わせたアプリじゃないと、速攻で審査してくれないようです。

ご利用は計画的に。

詳解 Swift

詳解 Swift

 

 

エンジニアが使うキーボードは東プレのリアルフォース1択!

東プレのREALFORCEを使い初めてから、1年以上経過しました。

f:id:kmatz90:20150715194712j:plain

もうこれに慣れてしまうと、他のキーボードには戻れません。

その理由を以下にまとめます。 

 

静電容量無接点方式を採用

文字だけでは全く意味が分からないですね。

ウルトラ簡単に言うと、最小限の力でタイピングできます。

セブンイレブンとかにあるATMのキーボード(ほぼテンキー)も、

同じ静電容量無接点方式を採用しているようなので、

試し打ちしたい人はセブンに行くといいかもw

 

小指などでタイプするキーは軽めに押せる仕様になっている

僕が購入したREALFORCEは91Uというシリーズで、

キーによって重さが異なっています。

例えば、「a」などの小指でタイピングする部分は、

キー荷重が軽めに設定されていて、

マジで無力で押せます

f:id:kmatz90:20150715194732j:plain

逆に「Enter」や「Esc」などは、

そう簡単に反応されるとマズイことがあるので、

それなりに力が必要です(とはいえ軽いけど)。

※キー荷重が統一されているシリーズもあります。

 

有線なので反応が良い

無線だとたまにラグが起きたりするので、あまり好きじゃないです。

また、電池などのバッテリーの心配もあります。

その点、リアルフォースは全シリーズ有線なので心配ありません。

 

Macにも使える(使ってる)

リアルフォースのキーボードはWindows仕様なので、

そのままだとMacでは使えません。

ですが、PCの環境設定を変更して、

「Seil」というソフトを入れれば、

Macでもリアルフォース(Windowsのキーボード)が使えるようになります。

詳細はこちらの方の投稿を参考にしてください。

 

さいごに

買うならテンキーが付いてない方がオススメです。

テンキーがない分スペースを取らないし、

マウスとの距離が近いので、右手の切り替えが高速でできます。

東プレ NG0100 REALFORCE91U

東プレ NG0100 REALFORCE91U

 
東プレ NG01B0 REALFORCE91UBK

東プレ NG01B0 REALFORCE91UBK

 

もっとギークなキーボードにHappy Hackingがありますが、

こちらはカーソルキーや「Ctrl」がないのでオススメしません。

完全にガチな人向けです。

SQLiteの注意点3つ!テーブル作成と同時にINDEX貼れないetc

最近SQLiteを触っています。

f:id:kmatz90:20150617185118p:plain

基本的な構文などはMySQLと同じですが、

決まりごとの違いや若干のクセがあるので、メモしておきます。

 

SQLiteのデータベースはファイルとして生成される

SQLiteはデータベースをファイルとして生成します。

なので、「ファイルを消す=DBを消す」ことになります。

 

SQLiteをインストールしたら(最近のLinuxはデフォで入ってるぽい)、

以下のコマンドで、DBができあがります。

sqlite3 dbname.sqlite3

上記の「.sqlite3」の部分は何でもいいです。

しかし、拡張子がないと、

のちのち何のファイルか分からなくなる可能性があるので、

慣習的に「.sqlite3」とするようです。

 

しかし、DBを作成しただけではファイルが作成されません

DBを作成し、さらにテーブルを作成しなければ、ファイルが生成されないようです。

「DB作ったのにファイルがない!」と焦りました。

 

ファイル(DB)のパーミッションに注意

PHPなどのプログラムからファイル(DB)にアクセスする場合、

ファイルの権限を考慮しないと、UPDATEやINSERTができません。

これは通常のDBと違うので、ハマるかも。

 

テーブル作成と同時にINDEXが貼れない

これは意外でした。

MySQLの場合、

「CREATE TABLE」すると同時にインデックスの設定ができたのですが、

SQLiteだと仕様の問題でできないようです。

むしろ、MySQLのように1度にできる方がマイノリティらしいです。

なので、1度テーブルを作成し終わってから、インデックスを貼る必要があります。

CREATE INDEX index_name ON table_name(column1, column2...)

まあ、仕方ないですね。

 

まとめ

最近使ったコマンドなどをまとめました。

その他、selectなどの命令文はMySQLとほぼ同じです。

 

SQLiteiOSやAndoridのアプリでも使うデータベースなだけに、

今後も使うことがありそうなので、

1度覚えたら忘れないようにしたいですね。

SQLite ポケットリファレンス

SQLite ポケットリファレンス