前回の「ブログシステムの深層:知られざる知識を明かす(三)」では、ブログプロトコルや標準について紹介しました。今回の最終章では、ブログシステムを設計する際に知っておくべきポイントを紹介します。
目次
記事が長くなるため、4回に分けて配信します。目次は以下の通りです。
- 「ブログ」の歴史
- 私のブログストーリー
- ブログの読者とは?
- ブログ基本機能の設計ポイント
- 4.1 記事(Post)
- 4.2 コメント(Comment)
- 4.3 カテゴリー(Category)
- 4.4 タグ(Tag)
- 4.5 アーカイブ(Archive)
- 4.6 ページ(Page)
- 4.7 購読
- 4.8 バージョン管理
- 4.9 テーマとカスタマイズ
- 4.10 ユーザーと権限
- 4.11 プラグイン
- 4.12 画像・添付ファイルの処理
- 4.13 不適切な言葉のフィルタリングとコメント審査
- 4.14 静的化
- 4.15 通知システム
- ブログプロトコルまたは標準
- 5.1 RSS
- 5.2 ATOM
- 5.3 OPML
- 5.4 APML
- 5.5 FOAF
- 5.6 BlogML
- 5.7 Open Search
- 5.8 Pingback
- 5.9 Trackback
- 5.10 MetaWeblog
- 5.11 RSD
- 5.12 リーダービュー
- ブログシステム設計の知識ポイント
- 6.1 タイムゾーンは本当にすべてUTC?
- 6.2 HTMLかMarkdownか
- 6.3 MVCかSPAか
- 6.4 セキュリティ
- おわりに
6.1 | タイムゾーンは本当にすべてUTC?
時間をUTCで保存するのは、2020年においてはエンジニアの間でほぼ常識となっている慣行です。ブログシステムも同様で、私のブログではすべての時間データを最終的にUTCで保存しています。しかしブログには特別な点があります。それは、読者のタイムゾーンに合わせてUTCを変換して表示するのではなく、ブログ作者のタイムゾーンに従って時間を表示すべきだということです。
これは技術的な理由ではなく、読者のタイムゾーンで表示してもコードが爆発するわけではありません。理由は、ブログの誕生の趣旨が個性を表現し、ブロガーがインターネット上に自分自身の展示スペースを持つことにあるからです。したがって、ブロガー自身の属性を強調することが非常に重要であり、ブロガーがいるタイムゾーンも読者がブロガーを理解する属性の一つです。そのため、正統なブログシステムはタイムゾーン設定オプションを提供し、それに従ってUTC時間を変換して表示します。WordPressや私のMoongladeブログシステムも同様です。ブログシステムが読者のタイムゾーンの時間に自動的に変換しないのは、純粋にあまり知られていない趣向のデザインですが、尊重しなければなりません。

ここで興味深いのは、検索エンジンはブログ記事の時間をどう解釈するかです。UTC時間だけを検索エンジンに伝え、ユーザーには表示しないのがベストです。方法は簡単で、HTML5のtimeタグのdatetime属性を使用するだけです。HTML5標準が普及して以降、検索エンジンはタグの内容から意味を推測するのではなく、タグの種類から意味を判断することを好みます。
C#では、ToString(“u”)はUniversal sortable date/time patternを指します。
<time datetime="@Model.PostModel.PubDateUtc.ToString("u")" title="GMT @Model.PostModel.PubDateUtc">@DateTimeResolver.GetDateTimeWithUserTZone(Model.PostModel.PubDateUtc).ToString("MM/dd/yyyy")</time>
先ほどのスクリーンショットの記事の場合、時間のHTMLは次のようになります。
<time datetime="2020-04-29 11:41:02Z" title="GMT 4/29/2020 11:41:02 AM"
>04/29/2020</time
>
6.2 丨 HTMLかMarkdownか
多くの技術者がブログシステムを開発する際、Markdownをエディタとして選びがちです。単なる技術ブログで自分だけが使うのであれば問題ありません。しかし、他人のためにブログシステムを作る場合、覚えておいてください。誰もがプログラマーではないし、誰もがMarkdownを好むわけではありません。

このような場合、WSIWYGのHTMLエディタ(TinyMCEなど)が良い選択肢です。HTMLエディタはMarkdownよりも高度なレイアウトをサポートします。MoongladeはHTMLとMarkdownの両方のエディタをサポートしています。

記事の内容をデータベースに保存する際、Markdown形式では生のコンテンツを選択する必要があります。後で編集できるようにするため、生成されたHTMLではなく、元のMarkdownを保存します。HTML形式の場合も、もはやエンコードして保存することは推奨されません。なぜなら、2020年現在、主流のデータベースはあらゆる種類のUnicodeを正しくサポートできるからです。記事に突然絵文字😂が現れても問題ありません。エンコードを使用すると、私のブログのようにある種の「福報」に直面する可能性があります:https://github.com/EdiWang/Moonglade/issues/280。さらに、エンコードとデコードのプロセスはパフォーマンスに影響を与えます。私のMoongladeブログシステムも、つい最近エンコードを排除する改造を完了しました。
6.3 丨 MVCかSPAか
コミュニティでブログシステムを書くプログラマーの多くはSPAアーキテクチャを好み、MVCを古いと軽蔑します。本当にそうでしょうか?この問題は、飛行機がなぜ直線で飛ばないのか、航空会社がルート設計を間違えているのか?ということに似ています。これについては以前、私のブログ記事「私の.NET Coreブログパフォーマンス最適化の経験まとめ」で書きました。
2014年以降、SPAの台頭に伴い、Angularなどのフレームワークがフロントエンド開発の主流になりました。これらが解決する問題は、フロントエンドの応答性を高め、Webアプリケーションをネイティブアプリケーションにできるだけ近づけることです。私も多くの友人から「なぜブログをAngularで書かないの?できないの?」と質問されました。

実はそう単純ではありません。実際、私の現在の職務の主な仕事はAngularを書くことですが、ブログの旧.NET Framework版の管理画面では以前angularjsやangular2を使っていました。一連の実践の結果、私のブログのようなコンテンツサイトではAngularのメリットは大きくないことがわかりました。
これは不思議なことではありません。フレームワークを盲目的に選ぶ前に、前提条件に注意する必要があります。SPAフレームワークが対象とするのは、実はWebアプリケーションです。アプリケーションとは、Azure PortalやOutlookメールのように、インタラクションが多く、Webページをアプリケーションとして開発することを目的としています。この場合、SPAはユーザー体験を向上させるだけでなく、開発コストも削減できるため、一石二鳥です。しかしブログはコンテンツ中心のサイトであり、アプリケーションではありません。強いて言えば、ブログの管理画面がアプリケーションになり得る程度です。ブログのフロントエンドで唯一のインタラクションはコメントと検索だけなので、SPAはこのような作業には適していません。これは、市場に買い物に行くのに、自転車の方が戦車より便利なのと同じです。
マイクロソフトの公式ドキュメントにも、SPAと従来型サイトをいつ選択すべきかについての参考資料があります。
ブログのフロントエンドにMVCを選ぶもう一つの理由は、この記事の冒頭「ブログの読者とは誰か」を思い出してください。私は10年以上ブログを運営してきましたが、統計データによると、ほぼすべてのユーザーは検索エンジンから来て、1つの記事だけを見て閉じます。よく考えてみてください。SPAが解決する最大の課題の一つは、部分的なリフレッシュのみでフロントエンドのパフォーマンス(応答性)を向上させることです。検索エンジンから来て1記事だけ見て閉じるユーザーに、SPAの部分リフレッシュの利点は本当に必要でしょうか?ユーザーは1記事だけ見るのに、SPAフレームワークを使うと、フレームワーク自体のファイル(ナビゲーション、インタラクションなどの機能を含む)を大量に読み込む必要があります。そして99%のユーザーは他の場所をクリックしません。つまり、たった1%のユーザーのために、巨大なフレームワークを読み込む価値があるでしょうか?これでパフォーマンスは向上するのでしょうか?それとも低下するのでしょうか?
MVCフレームワークは毎回サーバーサイドレンダリングされた完全なHTMLを出力しますが、99%のユーザーは1記事だけ見て閉じるため、その99%のユーザーにとって必要なリソースはSPAをロードするよりはるかに少なく、速度が速く、SEOにも優しいです。SPAはブログの管理ポータルには適していますが、フロントエンドには適していません。
6.4 丨セキュリティ
長年ブログを運営してきた管理画面の監視データによると、最も一般的な攻撃行為は全自動の脆弱性スキャンツールです。これらはdata.zip、wp-admin.php、gitディレクトリなどの一般的なセキュリティ上の見落としや、既知の脆弱性を悪用して攻撃しようとします。目的はサーバーを制御し、ブログページにユーザーに対する悪意のあるコード(ランサムウェア、マイニングなど)を埋め込むことです。また、サーバー自体をマイニングマシンにすることもあります。

ブログシステムを設計する際、一般的なセキュリティ対策はOWASP(https://owasp.org/)を参考にしつつ、柔軟性を確保します。例えば、JavaScriptのCSPを導入する場合、通常のブログユーザーがサードパーティの統計プラグイン(Azure Application Insights、国内のCNZZなど)を追加する可能性があることを考慮し、適切なホワイトリスト/ブラックリストや機能スイッチを設計します。
ほとんどの設計者はユーザー(読者)の入力を防ぐことを知っています。入力の入り口は通常コメントと検索機能だけです。しかし、ブロガーが管理画面で行う入力も防ぐ必要があることを忘れてはいけません。なぜなら、必ずしもブロガー自身が操作しているとは限らないからです。例えば、ブロガーのアカウントが盗まれ、ハッカーが管理画面でナビゲーションバーのリンクをハッカーのサーバーやlocalhost上に用意された奇妙な仕掛けに変更した場合(そうです、localhostが正常な人のコンピューターで機能しないと思わないでください)、読者は大きな影響を受けます。

管理画面ログインの認証については、成熟したSSOが利用できる場合は優先的にSSOを採用します。例えば、MoongladeはAzure Active Directory認証をサポートしており、マイクロソフトのような専門サービスを利用して認証を管理し、アカウントのセキュリティ問題を可能な限り回避できます。ユーザーがSSO環境を持たない場合にのみ、ローカルアカウント認証にフォールバックします。サードパーティサービスを使うより自分で書いた方が安全だとか、自分のロジックは誰も知らないからハッキングされないなどと考えてはいけません。世界トップレベルのエキスパートでない限り、自分で書いたシステムはサードパーティサービスよりもはるかにハッキングされやすいです。
また、敵対陣営の退屈なプログラマーによる攻撃もあります。例えば、スクリプトやツールを使ってブログシステムの特定のURLに継続的にリクエストを送り、DDOSのようにサーバーをダウンさせようとするものです。このような退屈なリクエスト送信者に対しては、ブログシステム設計者は該当するURLエンドポイントにレート制限を導入すれば十分です。実際のDDOS攻撃に対しては、クラウド上の抗DDOSサービスやハードウェアDDOSファイアウォールでのみ対処可能です。
最後に、OWASPにないものも忘れてはいけません。ブログのプロトコルにも設計上の欠陥があり、例えばpingbackはDDOSに利用される可能性があります(https://www.imperva.com/blog/wordpress-security-alert-pingback-ddos/)。また、サーバーポートのスキャンにも使われます(https://www.avsecurity.in/wordpress-xml-rpc-pingback-vulnerability/)。
おわりに
優れたブログシステムを設計するには、あらゆる細部を検討する価値があります。これらの設計は最初から正しくできるものではなく、長期間のブログ運営データを発見し、考えることでしか得られません。また、市場は変化し、ユーザーの行動は変化し、標準は廃止されたり新しく発明されたりするため、システムもそれに合わせて進化させる必要があります。
一見シンプルなシステムでも、ありふれて見えても、背後には見えない完全な体系があります。ブロックも同様です。電子商取引、フードデリバリー、金融決済システムはさらに複雑であり、表面的に見ただけで作り始めてはいけません。飛行機を作るのと同じで、紙飛行機と本物の飛行機は全く別物です。
技術者は何が流行っているかだけで選ぶべきではありません。優れた製品は最新の技術を詰め込んで作られるのではなく、まずユーザーが製品をどのように使うのかを分析し、最も適切な選択をしなければなりません。成功するためには、技術そのものだけに思考を限定せず、市場やユーザー行動を分析することで、より正確に技術を選択し適用できることを覚えておいてください。

ここまで読んでくださった読者の皆様、ご質問やご意見があれば、コメントでお知らせください。
次回は主に【ブログシステム設計の知識ポイント】について紹介します。ご期待ください。
