0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Shall we テックブログ? — データで見るQiitaとZennの比較

Last updated at Posted at 2025-12-28

はじめに

テックブログによるアウトプットが大事とかいう言説を聞くことが多くなりました。
Qiitaで100記事程度書いて、Zennでも100万文字程度の文章を書いた経験をもとに、今回は QiitaとZennの比較を行ってみようと思います。

Qiita
https://qiita.com/mima_ita

Zenn
https://zenn.dev/mima_ita

テックブログの歴史

ソフトウェアに関する自身が得た知見を、インターネットという大海に放流する行為はインターネットの黎明期から行われ続けていました。
当時はHTMLに直打ちしてFTPにアップロードするケースが多かったと思います。

1999年にはプログラミングに関する記事と知識を共有できるCodeProject1というサイトが開設され、プログラミングに関する記事を投稿したり知識を共有する場は古くから求められていたことがわかります。

さて、2000年代になるとブログという文化が登場し、個人の情報発信は、それ以前より容易となりました。同時にブログ文化の負の側面を取り込むことになりますが、今回はその問題については言及しません。2

2010年代になると、プログラムコードを投稿して、それが綺麗に表示できるような媒体が増えていき、代表的なものとしてQiitaが登場しました。
母国語で使えるCodeProjectのようなQiitaの存在は多くの人々を夢中にさせて、2020年頃には「日本のほとんどの(ソフトウェア)エンジニアが使用しているサイト」という言葉が出るほどの規模となります。
その頃にはZennというサービスも始まり、現在ではお手軽にテックブログを始めるならQiitaかZennのどちらかが選ばれることが多くなっています。

書きやすさの違い

Qiitaについては最近書いてないので数年前の感想にはなりますが、書きやすさについては、基本的な使い方の範囲においてはQiitaもZennも変わらないです。

編集画面

Zennは最近まで編集しながらプレビューをみる機能がありませんでしたが、最近サポートされるようになりました。

Qiitaによる編集画面

Zennによる編集画面

アコーディオンの書き方

アコーディオンの書き方はQiitaとZennで違いがあります。

アコーディオン このように折りたたむことができる。
  • Hello
  • World

Qiita

<details><summary>アコーディオン</summary>
このように折りたたむことができる。

- Hello
- World
</details>

Zenn

:::details アコーディオン
このように折りたたむことができる。

- Hello
- World

:::

図の書き方

mermaid記法はQiita、Zenn双方とも同じように利用できます。
コードブロックに「```mermaid」と入力してください。

sequenceDiagram
    participant M as M(マスタ)
    participant X as X(オブジェクト)
    participant Y as Y(オブジェクト)

    M->>X: call(X)
    X-->>M: detach
    M->>Y: call(Y)
    Y-->>M: detach
    M->>X: call(X)(繰り返し…)
    X-->>M: detach

Qiita

Zenn

動画の埋め込み

Qiitaの場合、以下のiframeを使用して動画の埋め込みが可能です。

<iframe width="560" height="315" src="https://www.youtube.com/embed/PGX_8uwzZBE?si=uxRprAASFTebYBCY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

なお、ZennはYoutubeのURLを貼り付けるだけで埋め込めることが可能です。

https://www.youtube.com/watch?v=PGX_8uwzZBE

数式

QiitaもZennも数式をサポートしています。

$x^2$でインラインの数式が記載可能になります。$x^2$という表示になっています。
複数行の数式の場合は$$を使用します。

$$
y = x^2 + 1
$$

$$
y = x^2 + 1
$$

ただし、Zennの新しいエディタだと数式のプレビューがうまくいかないようです。

Zennで数式のプレビューがうまくいかないケース

以下のように崩れるケースがある。

おそらく動的な反映がうまくいっていないようで、エディタを編集する前はちゃんと表示される。

Qiita固有の機能

Qiita固有の機能として優れているのは以下の2つです。

  • 編集履歴
  • 編集リクエスト

編集履歴は過去の編集履歴を確認できます。

編集リクエストは他人の記事に対して修正を提案できます。GitHubのプルリクエストのようなものです。

性善説に基づく運用をする限り、これらの機能はQiitaを使用するメリットとなり得るでしょう。

悪い使い方 編集履歴には全ての履歴が残ります。 すなわち、消したい過去もそのまま残っています。 たとえば、なんらかのコンプライアンスに違反する表現があったとしても、編集履歴に残り続けてしまうことになります。 最近燃えた記事についても編集履歴で初版の内容や時期を見ると、また別の感想を抱くことになるのではないかと思います。

編集リクエストについても、軽微な誤字やタグを追加するというものを上げ続けてkコントリビューションを荒稼ぎするというライフハックがありました。
最近は編集リクエストによるコントリビューションの点数と、一定期間における編集リクエストの送信数は制限されているようですが3、この手法でコントリビューションを稼いで賞を狙うことが過去には可能でした。

なお、GitHub Sponsorsと連携する支援サービスなるものもあるらしいですが、使っていないのでここでは言及しません。

Zenn固有の機能

Zenn固有の機能で特に優れているのは以下の2つです。

  • スクラップ

スクラップは簡易なメモを記録することができます。記事にするまでもない小ネタをマークダウンを使って記録できます。

本については、複数ページの記事をまとめることができます。
Zennの記事では8万文字程度の上限がありますが、本の機能を使うことで、その制限を超えることができ、適切なサイズで章立てすることが可能になります。

またAIレビューもサポートしており月10回使用可能です。

なお、収益とかもできるらしいですが、やっていないのでここでは言及しません。

読まれやすさの比較

2025年時点ではQiitaの方が読まれやすいと考えてよいでしょう。
実際、ここ数年、まったくなにも更新していないQiitaは48万PVを得ています。

一方Zennは更新しても1.5万PVです。

無論、書いている内容や記事の数の差がありますので公平な比較とはいえませんが、PVを稼ぎたいだけならQiitaの方が良いといえます。

利用者数の比較

最新値はわかりませんが、単純なユーザー数という意味では2025年時点ではQiitaの方が多いと考えられます。

2025年4月22日 会員数 150万人
https://corp.qiita.com/releases/2025/04/one-million-five-hundred-thousand/

2023年12月12日 会員数10万人、組織利用数500
https://classmethod.jp/news/20231212-zenn-members-100k/

2025年2月3日 エンジニアのための情報共有コミュニティ「Zenn」の利用組織数が1,000を突破
https://prtimes.jp/main/html/rd/p/000000397.000014901.html

これだけを見るとQiitaの方が活発なコミュニティーに見えます。
ただ、私の実感的に異なるように見えるので、もう少し深掘りしてみます。

Qiitaの年ごとの投稿数、投稿者数、リアクションの変化

私の感覚として2015年以前については書いた記事に対する反応が活発で、Qiitaの記事の露出も多かった印象です。
それは2020年あたりをピークにだんだん減っており、昨今はQiitaの記事をあまり見なくなった印象をもっています。
この印象が正しいかどうかをQiitaのAPIを使って検証します。
なお、API的には「page_views_count」でビュー数が取れるように見えますが、実際には自分の書いた記事のビュー数しか取得できていないようです。

2015/1/1 〜 2025/12/27の各項目を集計した結果は以下のとおりです。

投稿数 投稿者数 like平均 stock平均 like合計 stock合計 like最大 stock最大 like中央値 stock中央値
2015 53,246 9,968 31.64 30.66 1,684,724 1,632,263 12,784 13,220 7 7
2016 65,655 13,388 26.55 24.79 1,743,383 1,627,844 10,796 11,297 6 5
2017 69,005 16,263 21.38 19.16 1,475,646 1,322,337 9,752 7,488 4 4
2018 94,101 21,773 20.62 17.61 1,939,974 1,656,947 8,255 7,700 4 3
2019 122,111 28,157 15.79 12.77 1,927,556 1,559,466 5,923 6,456 3 2
2020 136,866 31,073 10.75 8.72 1,470,926 1,193,515 7,513 8,075 2 1
2021 108,663 26,569 7.28 5.70 790,905 618,956 8,402 6,270 1 1
2022 97,378 23,435 6.58 4.56 640,931 443,671 4,425 5,104 1 1
2023 98,167 23,470 6.43 4.55 631,113 446,493 4,160 3,624 1 0
2024 112,128 24,768 5.12 3.48 574,337 390,049 4,623 5,312 1 0
2025 121,540 24,632 3.46 2.08 420,820 253,054 1,793 1,903 0 0

※2025年は年途中時点の暫定値である。

投稿数は2020年をピークに一時期下がりましたが、徐々に復活しています。

投稿者数も2020年をピークに下がり回復していますが、頭打ちになっているように見えます。


おそらく、少数の人間が多くの記事を投稿するようになったのではないかと推測されます。

like数とstock数の平均中央値遷移は明確に右肩下がりです。

これは古い記事ほど、likeやstockをされる可能性があるので構造的にそうなりやすい結果と言えます。また、サービスが始めのころのユーザー数が少ない頃ほど平均や中央値が高くなるのも納得の結果です。
なお、2025年のLikeの中央値でいうと0なので、基本的に記事を書いても反応はされません。

一方、古いほど大きくなる傾向があるはずのLikeとStockの総数では、違った傾向が観測できます。

2019年、2020年をピークにしており単純な右肩下がりではありません。
これは5年程度はlike, stockがされて増える傾向があるが、それ以上は頭打ちになる可能性を示唆しているかもしれませんし、2020年になにかあったのかもしれません。

今回のデータを収集したプログラムは以下のようになります。

Qiitaの年ごとの遷移分析用プログラム

QiitaAPIを使用してSQLiteに記事情報を登録して分析をしています。
QiitaのAPIの都合でページネーションが100までの限界があるため、1日づつ取得しています。
また1時間あたり1000回のレート制限があるので、制限となったらヘッダの「Rate-Reset」をみて待機をして10年分取得します。10時間程度はかかる見込みです。

ライブラリのインストール

!pip install requests
!pip install requests-oauthlib
!pip install sqlalchemy
!pip install tqdm

Qiitaの操作クラス

"""Qiita APIを操作する.

QiitaAPIについては下記を参照してください。
https://qiita.com/api/v2/docs
"""

import math
import time
from datetime import datetime, timezone
from typing import Any, Callable, List, Tuple, Generator

import requests


class QiitaApi:
    """QiitaAPIを操作するクラス."""

    QIITA_API_URL = "https://qiita.com"
    interval = 1

    def __init__(self, access_token: str, *, timeout: float = 30.0):
        self._access_token = access_token
        self._timeout = timeout

        # コネクション(HTTP Keep-Alive / connection pool)を使い回す
        self._session = requests.Session()
        self._session.headers.update(
            {
                "Accept": "application/json",
                "Authorization": f"Bearer {self._access_token}",
            }
        )

    def close(self) -> None:
        """明示的にセッションを閉じたい場合に呼ぶ."""
        self._session.close()

    def __enter__(self) -> "QiitaApi":
        return self

    def __exit__(self, exc_type, exc, tb) -> None:
        self.close()

    @staticmethod
    def _query_all_page(
        query_method: Callable[[str, int, int], Tuple[str, List[Any]]],
        param: str,
    ) -> Generator[Any, Any, Any]:
        per_page = 100

        total_count, items = query_method(param, per_page, 1)
        for item in items:
            yield item

        loop_count = math.ceil(int(total_count) / per_page) if total_count else 0
        for page in range(2, loop_count + 1):
            time.sleep(QiitaApi.interval)
            _, items = query_method(param, per_page, page)
            if not items:
                break
            for item in items:
                yield item

    def _is_rate_limited(self, res: requests.Response) -> bool:
        if res.status_code != 403:
            return False
        try:
            body = res.json()
        except ValueError:
            return False
        return body.get("type") == "rate_limit_exceeded" or "Rate limit exceeded" in (body.get("message") or "")

    def _sleep_until_rate_reset(self, res: requests.Response, *, buffer_sec: float = 1.0, max_sleep_sec: float = 3600.0) -> None:
        """
        Rate-Reset ヘッダ(epoch秒)まで待つ。
        - buffer_sec: リセット直後のズレ対策で少し足す
        - max_sleep_sec: 異常値対策
        """
        reset = res.headers.get("Rate-Reset") or res.headers.get("Rate-Reset".lower())
        if not reset:
            # ヘッダが無い場合は短く待ってリトライ(保険)
            time.sleep(5)
            return

        try:
            reset_epoch = int(float(reset))
        except ValueError:
            time.sleep(5)
            return

        now = time.time()
        sleep_sec = (reset_epoch - now) + buffer_sec
        if sleep_sec < 0:
            sleep_sec = 0

        if sleep_sec > max_sleep_sec:
            sleep_sec = max_sleep_sec

        # ログが要るなら(不要なら消してOK)
        reset_dt = datetime.fromtimestamp(reset_epoch, tz=timezone.utc)
        print(f"[qiita] rate limited. sleeping {sleep_sec:.1f}s until Rate-Reset={reset_epoch} ({reset_dt.isoformat()})")

        time.sleep(sleep_sec)

    def _get(self, path: str, *, params: dict | None = None) -> requests.Response:
        url = f"{self.QIITA_API_URL}{path}"

        # レート制限時の自動リトライ(無限ループ防止で回数制限)
        max_retries = 3
        for _ in range(max_retries + 1):
            res = self._session.get(url, params=params, timeout=self._timeout)

            if res.status_code == 200:
                return res

            if self._is_rate_limited(res):
                self._sleep_until_rate_reset(res)
                continue

            # ここまで来たらレート制限以外のエラー
            raise Exception(res.status_code, res.reason, res.text)

        # ここに来るのは max_retries を超えた場合
        raise Exception("rate_limit_exceeded: exceeded retry limit", res.status_code, res.text)

    # ---- Items (user posts) ----
    def query_user_items(self, user_id: str) -> List[Any]:
        """ユーザが投稿した記事をすべて取得する"""
        return self._query_all_page(self._query_user_items_page, user_id)

    def _query_user_items_page(self, user_id: str, per_page: int, page: int) -> Tuple[str, List[Any]]:
        res = self._get(
            "/api/v2/items",
            params={
                "per_page": per_page,
                "page": page,
                "query": f"user:{user_id}",
            },
        )
        items = res.json()
        return res.headers.get("Total-Count", "0"), items

    # ---- Comments ----
    def query_comments(self, item_id: str) -> List[Any]:
        """指定の記事に紐づくコメントをすべて取得する"""
        return self._query_all_page(self._query_comments_page, item_id)

    def _query_comments_page(self, item_id: str, per_page: int, page: int) -> Tuple[str, List[Any]]:
        res = self._get(
            f"/api/v2/items/{item_id}/comments",
            params={"per_page": per_page, "page": page},
        )
        items = res.json()
        return res.headers.get("Total-Count", "0"), items

    # ---- Stockers ----
    def query_stokers(self, item_id: str) -> List[Any]:
        """指定の記事をストックしたユーザをすべて取得する"""
        return self._query_all_page(self._query_stokers_page, item_id)

    def _query_stokers_page(self, item_id: str, per_page: int, page: int) -> Tuple[str, List[Any]]:
        res = self._get(
            f"/api/v2/items/{item_id}/stockers",
            params={"per_page": per_page, "page": page},
        )
        items = res.json()
        return res.headers.get("Total-Count", "0"), items

    # ---- Stocks ----
    def query_stock(self, user_id: str) -> List[Any]:
        """指定のユーザがストックした記事をすべて取得する"""
        return self._query_all_page(self._query_stock_page, user_id)

    def _query_stock_page(self, user_id: str, per_page: int, page: int) -> Tuple[str, List[Any]]:
        res = self._get(
            f"/api/v2/users/{user_id}/stocks",
            params={"per_page": per_page, "page": page},
        )
        items = res.json()
        return res.headers.get("Total-Count", "0"), items

    def query_items(self, query: str, start_page: int = 1) -> Generator[Any, Any, Any]:
        """ユーザが投稿した記事をすべて取得する"""
        per_page = 100
        total_count, items = self._query_items_page(query, per_page, start_page)
        yield items

        loop_count = math.ceil(int(total_count) / per_page) if total_count else 0
        for page in range(2, loop_count + 1):
            time.sleep(QiitaApi.interval)
            _, items = self._query_items_page(query, per_page, page)
            if not items:
                break
            yield items

    def _query_items_page(self, query: str, per_page: int, page: int) -> Tuple[str, List[Any]]:
        res = self._get(
            "/api/v2/items",
            params={
                "per_page": per_page,
                "page": page,
                "query": query
            },
        )
        items = res.json()
        return res.headers.get("Total-Count", "0"), items

SQLite操作処理

from __future__ import annotations
import json
import math
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, Iterable, List, Tuple
from sqlalchemy import (
    DateTime,
    Integer,
    String,
    Text,
    create_engine,
)
from sqlalchemy.dialects.sqlite import insert as sqlite_insert
from sqlalchemy.orm import DeclarativeBase, Mapped, Session, mapped_column

class Base(DeclarativeBase):
    pass


class Article(Base):
    __tablename__ = "articles"

    # Qiita item ID を主キーにする
    item_id: Mapped[str] = mapped_column(String(64), primary_key=True)

    title: Mapped[str] = mapped_column(String(512), nullable=False)
    url: Mapped[str] = mapped_column(String(1024), nullable=False)
    likes_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    stocks_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    user_id: Mapped[str] = mapped_column(String(128), nullable=False)
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)
    tags_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]")

def _parse_qiita_datetime(s: str) -> datetime:
    # 例: 2025-12-27T21:24:52+09:00
    return datetime.fromisoformat(s)


def bulk_upsert_articles_sqlite(db: Session, items: Iterable[Dict[str, Any]]) -> None:
    """
    SQLiteに対して一括UPSERT(SELECTなし)
    - item_id 衝突時は UPDATE
    - ただし「値が変わるときだけ UPDATE」する(無駄UPDATEを避けて速度劣化を抑える)
    """
    rows: List[Dict[str, Any]] = []

    for it in items:
        tags = [t["name"] for t in (it.get("tags") or []) if isinstance(t, dict) and "name" in t]
        rows.append(
            {
                "item_id": it["id"],
                "title": it.get("title") or "",
                "url": it.get("url") or "",
                "likes_count": int(it.get("likes_count") or 0),
                "stocks_count": int(it.get("stocks_count") or 0),
                "user_id": (it.get("user") or {}).get("id") or "",
                "created_at": _parse_qiita_datetime(it.get("created_at") or datetime.now().isoformat()),
                "tags_json": json.dumps(tags, ensure_ascii=False),
            }
        )

    if not rows:
        return

    stmt = sqlite_insert(Article).values(rows)

    # 衝突時に更新する列
    update_set = {
        "title": stmt.excluded.title,
        "url": stmt.excluded.url,
        "likes_count": stmt.excluded.likes_count,
        "stocks_count": stmt.excluded.stocks_count,
        "user_id": stmt.excluded.user_id,
        "created_at": stmt.excluded.created_at,
        "tags_json": stmt.excluded.tags_json,
    }

    # 無駄UPDATE回避: いずれかの列が変わるときだけ UPDATE
    # (衝突はしても値が同じなら UPDATE しない)
    change_predicate = (
        (Article.title != stmt.excluded.title) |
        (Article.url != stmt.excluded.url) |
        (Article.likes_count != stmt.excluded.likes_count) |
        (Article.stocks_count != stmt.excluded.stocks_count) |
        (Article.user_id != stmt.excluded.user_id) |
        (Article.created_at != stmt.excluded.created_at) |
        (Article.tags_json != stmt.excluded.tags_json)
    )

    stmt = stmt.on_conflict_do_update(
        index_elements=["item_id"],
        set_=update_set,
        where=change_predicate,
    )

    db.execute(stmt)  # executemany の一括実行になる
    db.commit()

def make_sqlite_engine(db_filename: str = "qiita.sqlite3"):
    # 「実行場所」ではなく「このファイルと同じディレクトリ」に固定したい場合
    return create_engine(
        f"sqlite:///{db_filename}",
        future=True,
        echo=False,
        connect_args={
            "timeout": 30,  # ロック待ち
        },
    )

収集のメイン処理

from datetime import date, timedelta
from tqdm import tqdm

# Qiitaの設定画面からアクセストークンを作ってください。
access_token = "TODO"

engine = make_sqlite_engine("qiita.sqlite3")
Base.metadata.create_all(engine)
with Session(engine) as db:
    with QiitaApi(access_token) as api:
        with Session(engine) as session:
            start = date(2015, 1, 1)
            end   = date(2025, 12, 31)
            days = (end - start).days
            for i in tqdm(range(days + 1)):
                d = start + timedelta(days=i)
                next_d = d + timedelta(days=1)
                query = f"created:>={d.isoformat()} created:<{next_d.isoformat()}"
                for items in api.query_items(query):
                    bulk_upsert_articles_sqlite(session, items)

年ごとの投稿数、平均/最大/中央値/総 Like、平均/最大/中央値/総 ストック

WITH base AS (
  SELECT
    strftime('%Y', created_at) AS year,
    likes_count,
    stocks_count
  FROM articles
  WHERE created_at IS NOT NULL
),
ranked AS (
  SELECT
    year,
    likes_count,
    stocks_count,
    ROW_NUMBER() OVER (PARTITION BY year ORDER BY likes_count)  AS rn_likes,
    ROW_NUMBER() OVER (PARTITION BY year ORDER BY stocks_count) AS rn_stocks,
    COUNT(*)      OVER (PARTITION BY year)                      AS cnt
  FROM base
)
SELECT
  year,
  cnt,
  SUM(likes_count)  AS sum_likes_count,
  SUM(stocks_count) AS sum_stocks_count,
  MAX(likes_count)  AS max_likes_count,
  MAX(stocks_count) AS max_stocks_count,
  AVG(likes_count)  AS avg_likes_count,
  AVG(stocks_count) AS avg_stocks_count,
  -- 中央値(偶数なら中央2つの平均)
  AVG(CASE WHEN rn_likes  IN ((cnt + 1) / 2, (cnt + 2) / 2) THEN likes_count  END) AS median_likes_count,
  AVG(CASE WHEN rn_stocks IN ((cnt + 1) / 2, (cnt + 2) / 2) THEN stocks_count END) AS median_stocks_count
FROM ranked
GROUP BY year
ORDER BY year;

年ごとの投稿者数

select 
   year,
   count(*)
FROM (
  SELECT distinct strftime('%Y', created_at)  AS year, user_id
  FROM articles
  group by year, user_id
 ) AS TBL GROUP BY year;

はてなブックマーク上のZennとQiitaの比較

前述のデータだけだとQiitaのLikeとStockによる反応の年ごとの遷移については判断がつきませんでした。

本来であればQiitaAPIを使用した分析と同じことをZennのAPIを使用して集計して比較するのが筋ですが、ZennのAPIはQiitaとことなり公開されたものではありません4

今回は、はてなブックマークでQiitaとZennの年間のブックマーク数を比較してみることとします。技術者全体の傾向はわかりませんが、はてなブックマーク文化圏における相対的関心の比較は行えます。
はてなブックマークも、古い記事ほどつけられる可能性はないとは言えませんが、多くの場合、ブックマークの時期は最初が多く、その後はほとんど増えない傾向があります。

検証方法として以下のURLで取得したブックマーク数を集計します。

https://b.hatena.ne.jp/q/https://qiita.com?target=text&sort=popular&users=1&safe=on&date_begin=2025-01-01&date_end=2025-12-31
or
https://b.hatena.ne.jp/q/https://zenn.dev?target=text&sort=popular&users=1&safe=on&date_begin=2025-01-01&date_end=2025-12-31

date_begin、date_endを調整して1年ごとに集計します。
usersはブックマーク数の足切りです。はてなブックマークは一般的に3以上のブックマークされると新着にのり伸びやすくなります。今回は1のケースと3のケースをそれぞれ集計します。


※2025年は年途中時点の暫定値である。

はてなブックマークの年ごとの遷移

はてなブックマーク(3以上)の年ごとの遷移

Qiitaの年毎のはてなブックマーク数(1以上)は2020年をピークに落ちています。
Zennのはてなブックマーク数は右肩あがりです。
特にはてなブックマーク数3以上のものに関しては2024年でQiitaとZennは逆転しています。
つまり、今後の成長性という意味ではZennの方に分があると考えられます。

まとめ

今回はテックブログを書く場合の候補となるQiitaとZennの比較を行いました。
現時点で単純なPVを考える場合、Qiitaの方に分があり、将来性を考えるとZennの方に分があるように思えます。

また、10年前と違ってテックブログを書いたからといってポジティブな反応が返ってくるのが難しい時代になっているように見えます。
良いことなのか悪いことなのかはわかりませんが、すくなくともQiitaに書けば、はてなブックマークに取り上げられてバズるような時代ではなくなったと言えるでしょう。

おそらく、PVや「いいね」による射倖心を満たすことは難しくなっていると思います。その上でテックブログを何故書くかを見つめ直す時代になったのかもしれません。

なお、ほとんど同じマークダウンをZennに投稿しました。
違いを見てみるのも面白いかもしれません。
https://zenn.dev/mima_ita/articles/f78dcbef2a81d3

  1. 2000年代にWindowsプログラミングを行っていた人の多くはCodeProjectには助けられた経験が多いかと思います。残念なことに2025年現在、CodeProjectは閉鎖されています。

  2. 釣りタイトル/クリックベイトといった過激なタイトルで注目をあつめたり、怒りや憤り焦りを煽りアクセス数を稼ぐというテックブログの存在は簡単に確認することができるかと思います。

  3. 編集リクエスト受諾時のContributionの高さの意図についての質問 #164

  4. 内部で使用するAPIはありますが、動作は保証されていませんし、今回のように数年分の全記事を取得するという用途では使えませんでした。APIについて #209 を参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?