この度、弊社(エヌ次元株式会社)は、Publishersというメディアのシステム運用を担当することになりました。
知らないという人がほとんどかなと思いますので説明しますと、最近、乗りに乗った、cakes(ケイクス)とかnote(ノート)に近いものだと考えていただければ良いのですが、実際は、もうちょっとニッチな話題を取り扱ったメールマガジン配信システムです。
引き継ぎの話から、中〜大規模サイトでもすぐにできるメンテナンスの例を示していこうと思います。
Publishersというサービスのシステム運用を引き継ぎました
Publishersは、元々、運営は全て株式会社エートゥジェイが行っておりました。そこから、システム運用部分だけを切り出した形です。
もう少し具体的に、今回の引き継ぎの内容は、
- 利益を折半する形(レベニューシェア)
- 運用を全面的にバックアップすること
- 著作権に関する取り決め
- こういうところに記事を書いてよいか
- 弊社はその他の運用はしない
などを話し合った上で、システム運用の部分のみ弊社(エヌ次元株式会社)がしていくことになりました。とても貴重な機会ですし、努力の分だけ報われるレベニューシェアの形であります。
しかし、この時点で、僕がほとんど頭を使わなかったとしても、毎月、ちょこちょこっとした運用作業が生まれるため、弊社は工数に掛かる費用を肩代わりする形にはなります。
※ ユーザの方が見るといけないので、 Publishersは、ずっとまともに黒字で推移しています。サービス向上のために弊社が入った形です。 ご安心下さい。
おいしいかおいしくないか
弊社にとっておいしい話だったかというと、正直、今のところはおいしい話ではないです。これから、半年ぐらいは結構やること多くて地獄です。
ただ、割りとニッチな話題を扱ったメディアが集まっており、僕としては、社会的な使命をすごい感じております。
そして、苦しい時期を乗り越えさえすれば、継続的にお金が入ってくる仕組みではあるので、今は我慢というところです。今後の、Publishersの活躍に期待です。
個人の皆さまへおいしいはなし
meeti「ミートアイ」の件も最近ありましたが、このように引き取り先があるサービスはまだラッキーです。
他にも運用に苦しんでいるメディアは多々あるかと思います。僕の周りでもここ半年でひっそりと閉じてしまったメディアがいくつかあったりします。もったいない。残念であります。
メディアの個人化と言わずとも、小規模経営は、これからどんどんあり得るかなと思います。
優良なメディアを作っていかに一番いいところで売りぬけるかはすごくスリリングなビジネス。
売り抜けないor無駄に高いところで買ってしまったメディアはタダ同然で売るしかなくなる。凄く残念。— わいさわ (@yoshiiiine) 2017年2月21日
この もったいない は、実はビジネスチャンスです。 個人開発者は特にアンテナ張っておくとよい です。企業だと苦しい収益モデルでも、個人だったらがんばれば生活ができるレベルの儲けがでるかもしれません。
経験上、 WordPress などの汎用的なフレームワークで作られたサイトも、運用と共に、メンテナンス費用が膨らんでいく傾向にあり、システム運用費が捻出できなくなることがあります。WELQ などの事件もあり、記事あたりの単価も上がることが予想されます。こういった原価が想定以上に掛かってしまうと企業だと継続するのが辛くなってきます。
そこで、
- システム
- デザイン
- 執筆
- 編集
などのうち、どれか1つ以上のスキルがあって、原価を最小限に抑えられる個人であれば、メディアを将来において継続的に運用できます。
好みのメディアがあった場合、編集者やシステムエンジニアとして入り込んで、つばを付けておくのも一つありかなと思います。サービスが死にそうな匂いがしてきたら、涼しそうな顔で現れて、「もしよかったら、僕にください」というだけです。
※ 念を押しておきますが、 Publishersは、黒字で推移しています。運用には問題ありません。 ご安心下さい。
蓋を開けてみて
ここからは、Publishersのシステム運用を引き継いでからの話です。
今回、ソースコードやサーバー構成を見渡して、知ってはいましたが、すごく開発しにくい状況であることを改めて認識しました。メンテナンスしないまま錆びついてしまった感覚があります。
課題を簡単に挙げると、
- AWS の古いインスタンスを使っている
- 無駄にインスタンスが立ち上がっていて管理しきれていないし金が掛かる
- 全部 HTTPS にしたい
- MercurialではなくてGitにしたい
- IE8サポートをやめたい
- Lessを止めてSassにしたい
- Lessのソースが汚いのでリファクタリングしたい
- JavaScriptの管理が微妙
- CoffeeScriptにしたい
- Python や ライブラリが古い
などです。他にもあるかと思いますが、ぱっと思いついたものであります。
いくつかかい摘んで話をしていくと、AWS の古いインスタンスは、移行するのがちょっと怖いですが、コストパフォーマンスの問題でどうしても不利になっているために、利益率を上げるためになるべくはやく対策を打っていきたい問題です。
インスタンスの管理に関しても、t1.micro などの性能が低く、使えないものに関しては、スケールアップするなり、他のサーバに移行する必要があります。
あとは、基本的にはフロントエンドの問題ですね。IE8サポートはすぐに止めてしまいましょう。LessはSassとの競争で負けてしまったので、情報が少ないですし、 Compass
などの恩恵が受けられないので、早急に止めてしまいましょう。
今回やること
今回、時間の関係でサーバサイド少なめにフロントエンドを中心に、
- 無駄にインスタンスが立ち上がっていて管理しきれていないし金が掛かる
- MercurialではなくてGitにしたい
- IE8サポートをやめたい
- Lessを止めてSassにしたい
- Lessのソースが汚いのでリファクタリングしたい
の順に話を進めていきたいと思います。
サーバサイドやるのは、もうちょっとまとまった時間と心に余裕がないといけないので、忙しいときにはできません。ごめんなさい。
1. ブログ及びテストサーバを移行
ちょっとでもAWSを使ったことある人ならば、いかに管理できてなかったのかが解ってしまいそうです。ひどいスクリーンショットです。
あまり見られないコンテンツを、AWSではなくて、手頃なサーバに移行しました。もともと所持していた、さくらインターネットのVPSで十分だったので、まとめて引越しです。
これは、わりとスムーズにでき、2,000円位毎月運用費用が浮くことになりました。将来の利益アップに繋がりますね。
AWSでもリザーブドインスタンスにすればという意見もあるかと思いますので、そちらは、Webサーバで今後試していこうと思います。
2. MercurialやめてGitに移行
Mercurial をやめて、 Git に移行しました。これは、Backlogというサービスをプロジェクト管理に使っているので、 Git じゃないと連携できないというのが理由です。
やることといえば、
$ git init
$ rm -rf .hg
$ mv .hgignore .gitignore
$ git add .
$ git commit -m "add: the first commit"
くらいかなと思います。苦労することなく移行できました。
その他、デプロイ(本番反映)コマンドが、一部、 Mercurial(hg) を使ったものだったので、 git に書き換えたりしました。
3. IE8のサポートを終了
今後の運用が大変になると思うので、 IE8 は早急に殺さないといけません。
一応、上に確認を取っておきましょう。
一瞬で返事が来ました!意思決定がシンプルで速いことは素晴らしいです。
これで、心置きなくIE8サポートを除去することができます。
<!--[if lt IE 9]>
<link rel="stylesheet" href="/static/css/hoe.ie8.min.css" type="text/css" media="all">
<![endif]-->
のようなIE8向けのスタイルシートを全て廃止しました。
4. Less to Sass
現代、CSS のメタ言語の圧倒的勢力は Sass に傾いています。 Less のままメンテナンスしていく意味がほとんどなくなってしまったので、 Sass に速くしてしまえば、今後の改修スピードが上がります。
では早速、 Less から Sass にコンバートします。
brauliobo/less2sass を使って、
$ npm install less2sass
$ less2sass templates/sass
$ rm templates/sass/*.less
これで、 .less
が .scss
になるはずです。
ただ、less2sass
だと、ほとんど正規表現で修正するだけなので、文法上の細かいミスがどうしても出てしまいます。
Error: Invalid CSS after "...n-FontAwesome()": expected "{", was ";"
on line 5 of templates/sass/font-awesome/mixins.scss
from line 28 of templates/sass/font-awesome/font-awesome.scss
from line 33 of templates/sass/bootstrap/bootstrap.scss
from line 7 of templates/sass/manage.sass
Use --trace for backtrace.
とか、
Aborted due to warnings.
Error: 2.14286/em isn't a valid CSS value.
on line 45 of templates/sass/font-awesome/core.scss
from line 30 of templates/sass/font-awesome/font-awesome.scss
from line 33 of templates/sass/bootstrap/bootstrap.scss
from line 2 of templates/sass/main.sass
Use --trace for backtrace.
です。置換ミスで 2.14286/em
などのような、正しいプロパティの値にならなかったものが10数個出てしまいました。全体で10,000行以上あるソースなので、しょうがないかと思います。泣きながら、手で取り除いていきました。
GruntでWatch
Sassのファイルを監視しながらCSSのソースを変更するというところが、うまく動かなくなっていたので、Gruntで新規に書き直しました。
{
"name": "publishers",
"version": "0.1.0",
"devDependencies": {
"grunt": "^0.4.5",
"grunt-contrib-jshint": "^0.10.0",
"grunt-contrib-nodeunit": "^0.4.1",
"grunt-contrib-sass": "^1.0.0",
"grunt-contrib-uglify": "^0.5.1",
"grunt-contrib-watch": "^1.0.0"
}
}
などとして、package.json を作成後、
$ npm install
です。そして、
module.exports = (grunt) ->
pkg = grunt.file.readJSON 'package.json'
grunt.initConfig
sass:
dist:
files:
'static/css/main.css': 'templates/sass/main.scss'
'static/css/manage.css': 'templates/sass/manage.scss'
watch:
files: ['templates/sass/*.scss']
tasks: ['sass']
for t of pkg.devDependencies
if t.substring(0, 6) is 'grunt-'
grunt.loadNpmTasks t
grunt.registerTask 'default', ['sass']
みたいな Gruntfile.coffee
をプロジェクトルートに設置して、
$ grunt watch
コマンドです。これで、Watchできるようになりました。
フロントエンジニアなら、このへんは、
Ball を Goal に Doooooon!!! https://t.co/JgaDcgqNGS
— ぽうひろ?アーバンナックル (@pouhiroshi) 2017年2月21日
と爽快にやりたいところですが、もちろん、検索しながらやりました。
No more .scss!
このままだと、拡張子が、 .scss
なので、Sassの本来の気持ちよさを発揮できません。 Sassの拡張子は、 .scss
と .sass
があるのですが、前者の方がCSSの文法により近く、デザイナやマークアップエンジニアには好まれるようです。
しかし、 .scss の読みやすさや書きやすさは、即ち、自由に書けるということであり、コーディング規約を定めないときれいに書くことができませんし、ミスも見逃してしまいがちです。一方、 .sass ならば、構文がかなり厳しいので、文法上のミスをコンパイルエラーという形で気づくことができます。
といっても、 CoffeeScript や Python 、 Ruby 、 Yaml といった言語を1度でもかじったことがある方ならばすぐに、理解ができる文法かと思います。
よく編集するソースは全て変換していきます。
for f in *.scss; do sass-convert $f ${f%scss}sass ; done
rm *.scss
このとき、IE8などのレガシーなブラウザのための、プロパティを使っていたりするとうまくいかないことがあるので、注意してください。
Gruntfile.coffee
も書き直して、
module.exports = (grunt) ->
pkg = grunt.file.readJSON 'package.json'
grunt.initConfig
sass:
dist:
files:
'static/css/main.css': 'templates/sass/main.sass'
'static/css/manage.css': 'templates/sass/manage.sass'
# (省略)
のようにしました。これで、Sassがコンパイルできるようになりました。とてもコーディングしやすい環境が整いましたね。
Compassも導入する
やっぱり、 Compass
使いたいよね。ということで、導入してみます。
$ npm install grunt-contrib-compass --save-dev
$ npm install grunt-contrib-copy --save-dev
として、Compass のライブラリをインストール。
ディレクトリ構成を、ちょっとばかし変えて、
/templates/css/sass # Sassファイルを格納, Webサーバからは不可視
/templates/css/src # Sassコンパイル後のCSSを格納, Webサーバからは不可視
/static/css # Webサーバ上のリソース
のような感じで、上から下にファイルが流れていくように考えます。
そして、 Compass を使うためには、
# Set this to the root of your project when deployed:
http_path = '/'
http_stylesheets_path = '/static/css'
http_javascripts_path = '/static/js'
http_images_path = '/static/img'
css_dir = File.join('templates', 'css', 'src')
sass_dir = File.join('templates', 'css', 'sass')
images_dir = File.join('static', 'img')
javascripts_dir = File.join('static', 'js')
generated_images_dir = File.join('static', 'img')
# You can select your preferred output style here (can be overridden via the command line):
# output_style = :expanded or :nested or :compact or :compressed
output_style = :compact
# To enable relative paths to assets via compass helper functions. Uncomment:
# relative_assets = true
# To disable debugging comments that display the original location of your selectors. Uncomment:
# line_comments = false
line_comments = false
# If you prefer the indented syntax, you might want to regenerate this
# project again passing --syntax sass, or you can uncomment this:
# preferred_syntax = :sass
# and then run:
# sass-convert -R --from scss --to sass sass scss && rm -rf sass && mv scss sass
を compass_config.rb
として、プロジェクトルートに置いて、 Gruntfile.coffee
を以下のように変更します。
module.exports = (grunt) ->
pkg = grunt.file.readJSON 'package.json'
grunt.initConfig
compass:
dist:
options:
config: 'compass_config.rb'
copy:
css:
expand: true
cwd: 'templates/css/src'
src: ['*.css']
dest: 'static/css'
filter: 'isFile'
watch:
sass:
files: ['templates/css/sass/*.sass', 'templates/css/sass/*.scss', 'templates/css/sass/*/*.scss']
tasks: ['compass']
copy:
files: ['templates/css/*.css', 'templates/css/*/*.css']
tasks: ['copy']
for t of pkg.devDependencies
if t.substring(0, 6) is 'grunt-'
grunt.loadNpmTasks t
grunt.registerTask 'default', ['compass', 'copy']
Compass は、先頭に アンダースコア _
が、付いていないファイルを 勝手にコンパイルしてしまう ので、
$ rename 's/^/_/' *.sass
などとして、 コンパイルしたくないファイルの先頭にアンダースコアを付けて しまいましょう。
5. CSSのリファクタリング
このあと、5,000行以上ある、CSS(Sass)のソースをリファクタリングしたわけですが、
body.Portal.Top #frontispiece .Top-login-text,
body.Portal.Top #frontispiece .Top-signup-text
width: 500px
margin: 10px auto
body.Portal.Top #frontispiece .Top-login-text .btn-primary
width: 44%
body.Portal.Top #frontispiece .btn-facebook
width: 68%
などのソースが結構あって、マークアップに慣れていないエンジニアが力技で書いた感じがすごいしました。
上記のソースコードを、Sassらしく書き直すと
body.Portal.Top
#frontispiece
.Top-login-text,
.Top-signup-text
width: 500px
margin: 10px auto
.Top-login-text .btn-primary
width: 44%
.btn-facebook
width: 68%
となります。
あと、 body.Portal.Top
などを上の階層に入れると、描画性能低下に繋がったり、コンポーネントを汎用的に使うことができなくなるので、あまりよくありません。共通のコンポーネントを定義していくともれなく !important
地獄になるので注意が必要です。
今回は、ソース全体を確認して必要なさそうな body
を取ることで .Portal.Top
とすることで、お茶を濁しますが、このようなリファクタリングを今後5,000行以上に渡ってしていかないといけませんね。さもなくば、スタイルシートの変更のたびにつまずくことになってしまいます。
最後に
以上のように、フロントエンドを中心に改善してきましたが、まだまだ、やることが、
- 引き続きAWSのコストカット
- パフォーマンスアップ
- 全部 HTTPS にしたい
- JavaScriptの管理
- CoffeeScriptの導入
など、たくさんありそうです。今後も、Publishersを例に中〜大規模なサイトの改善案を示していければと思っております。
どうぞよろしくお願いします。
この記事を読んだあとに
- 書いた人のツイッター – Follow me!
- 『売上を3年連続20%成長させた18の秘訣』
- 運営しているアクションゲーム