هفت مخزن ترند گیت‌هاب که این هفته برای کار ایجنت بررسی کردم، بین ۲۸۳۲ و ۴۳۰ ستاره دارند؛ اما وقتی ستاره را بر سن روز تقسیم کنیم، ترتیب کامل عوض می‌شود. رکورد ستاره به رتبه‌ی پنجم می‌افتد و رکورد ۴۳۰ ستاره به رتبه‌ی اول. بیشترین جابه‌جایی پنج پله است. توضیف این است که ستاره یک انباشت است و سرعت یک نرخ، و برای انتخاب چیزی که قرار است زیر بار واقعی بگذارید نرخ همان چیزی است که اهمیت دارد. همه‌ی عددها از رابط برنامه‌نویسی گیت‌هاب خوانده شده و زمان خواندن داده ثبت شده است.

ترند گیت‌هاب یک فهرست مرتب بر اساس ستاره می‌دهد، و این فهرست برای دو کار کاملاً متفاوت به کار می‌آید. اگر دنبال کتابخانه‌ای هستید که سال‌ها نگه داشته شده، ستاره معیار خوبی است، چون هزاران نفر قبل از شما از آن استفاده کرده‌اند. اگر دنبال چیزی هستید که می‌خواهید این هفته روی آن حساب کنید، ستاره تقریباً بی‌ربط است، چون مخزنی که پارسال ساخته شده و امروز ۲۸۳۲ ستاره دارد، از مخزنی که سه سال است کار می‌کند و ۱۱۴۸ ستاره دارد جلوتر ایستاده است.

این نوشته روش تبدیل یک فهرست ستاره به یک فهرست تصمیم را نشان می‌دهد: چهار معیار که با هم خوانده می‌شوند و هر کدام چیزی را می‌گویند که دیگری نمی‌گوید.

یک تصویر، نه هفت درخواست

اولین خطایی که در چنین بررسی‌ای مردم می‌کنند این است که هر مخزن را جداگانه می‌پرسند. هر درخواست زمان خودش را دارد و ستاره‌ها در این فاصله حرکت می‌کنند، پس جدولی که از داده‌های ناهم‌زمان ساخته شود، در جدولش عددهای ناسازگار دارد. راه درست یک زمان مرجع واحد و یک خواندن پیوسته است.

<span class="code-comment"># triage_snap.py -- یک زمان مرجع، هفت خواندن، یک جدول</span>
import json, time, urllib.request
from datetime import datetime, timezone

NOW = datetime.now(timezone.utc).replace(microsecond=0)
SEVEN = ["makecindy/cindy", "HarnessRouter/harnessrouter",
         "duty1g/x64dbg-mcp-server",
         "Dicklesworthstone/coding_agent_session_search",
         "qiz029/dscode", "mikehasa/golive-skill", "cloudshipai/station"]

def repo(full):
    with urllib.request.urlopen(urllib.request.Request(
            f"https://api.github.com/repos/{full}",
            headers={"User-Agent": "triage"}), timeout=40) as r:
        return json.load(r)

snap = {"read_at": NOW.isoformat(), "repos": []}
for full in SEVEN:
    d = repo(full)
    c = datetime.fromisoformat(d["created_at"].replace("Z", "+00:00"))
    age = (NOW - c).total_seconds() / 86400
    st = d["stargazers_count"]
    snap["repos"].append({
        "name": full, "stars": st, "forks": d["forks_count"],
        "age_days": round(age, 2),
        "stars_per_day": round(st / age, 1),
        "idle_days": round((NOW - datetime.fromisoformat(
            d["pushed_at"].replace("Z", "+00:00"))).total_seconds() / 86400, 1),
        "fork_ratio": round(d["forks_count"] / st, 3),
    })
    time.sleep(0.8)

json.dump(snap, open("triage_snapshot.json", "w"), ensure_ascii=False)

زمان خواندن داده در همان فایل ذخیره می‌شود. این یک تشریفات نیست: ستاره در ساعت‌ها حرکت می‌کند و بدون ثبت زمان، خواننده نمی‌تواند بفهمد عدد کهنه است یا غلط.

چهار معیار، و اینکه هر کدام چه چیزی را می‌گویند

سنجش درست وقتی است که هر معیار کاری بکند که دیگری نمی‌کند. ستاره می‌گوید چقدر توجه جمع شده، سرعت روزانه می‌گوید توجه چقدر تازه است، نسبت فورک می‌گوید چند نفر قصد استفاده‌ی واقعی داشته‌اند، و روزهای بی‌کاری می‌گوید پروژه هنوز زنده است یا نه.

رتبه‌ی ستارهمخزنستارهسن روزستاره بر روزرتبه‌ی سرعتجابه‌جایینسبت فورک
۱makecindy/cindy۲۸۳۲۶۷٫۸۰۴۱٫۸۵‎−۴۰٫۱۵۱
۲HarnessRouter/harnessrouter۲۷۳۲۴۹٫۶۹۵۵٫۰۳‎−۱۰٫۱۰۱
۳duty1g/x64dbg-mcp-server۲۱۳۱۳۶٫۹۴۵۷٫۷۲‎+۱۰٫۱۰۲
۴Dicklesworthstone/coding_agent_session_search۱۱۴۸۳۱۱٫۴۸۳٫۷۶‎−۲۰٫۱۲۲
۵qiz029/dscode۷۳۵۱۷٫۱۴۴۲٫۹۴‎+۱۰٫۰۰۱
۶mikehasa/golive-skill۱۰۳۰۴٫۹۷۲۰۷٫۱۱‎+۵۰٫۰۷۳
۷cloudshipai/station۴۳۰۴۲۶٫۶۳۱٫۰۷۰۰٫۰۹۳

ستون آخر را از خود داده بازمحاسبه کنید، نه از جدول. هر نسبت فورک یعنی فورک تقسیم بر ستاره است و هر نرخ روزانه یعنی ستاره تقسیم بر سن روز. اگر این دو محاسبه با چیزی که در جدول نوشته‌اید نخواند، یا داده کهنه است یا اشتباه تایپی دارید.

دو جابه‌جایی بزرگ، دو داستان متفاوت می‌گویند. مخزن ششم با ۱۰۳۰ ستاره و تنها ۴٫۹۷ روز سن، ۲۰۷ ستاره در روز می‌گیرد و از رتبه‌ی ششم به رتبه‌ی اول می‌آید. این نرخ در گیت‌هاب کم‌سابقه است و به‌تنهایی دلیل کافی برای اعتماد نیست؛ چنین نرخی معمولاً یک موج اشتراک‌گذاری در یک فهرست یا یک پست پرمخاطب است، نه رشد پیوسته. در مقابل، مخزن چهارم با ۳۱۱ روز سن و ۱۱۴۸ ستاره، روزی ۳٫۷ ستاره می‌گیرد. این مخزن رشد ندارد، اما هنوز فعال است و این دو وضعیت کاملاً متفاوت‌اند.

نسبت فورک سومین صافی است و در این جدول یک مورد را بیرون می‌اندازد. مخزن پنجم با ۷۳۵ ستاره، فقط یک فورک دارد و نسبتش ۰٫۰۰۱ است. یعنی تقریباً هیچ‌کس مخزن را برای کار خودش برداشته نیست. این برای یک کتابخانه‌ی خواندنی طبیعی است و برای چیزی که قرار است روی آن حساب کنید یک هشدار است. در شمارش دانلود هفتگی همین کار را از سمت دیگری می‌کند: به‌جای پرسیدن از ریپازیتوری، مصرف واقعی بسته را می‌پرسد و ستاره را کنار می‌گذارد.

روزهای بی‌کاری، چهارمین معیار است و در جدول بالا نیامده چون ستون را جا ندادیم، ولی دو مورد را جدا می‌کند. مخزن هفتم ۲۴۴ روز است که تغییری نداشته، یعنی عملاً متوقف است و ۴۳۰ ستاره‌اش فقط توجه تاریخی است. مخزن سوم هم ۱۱ روز بی‌کار بوده که برای یک ریپازیتوری فعال کمی نگران‌کننده است. بقیه در چند روز اخیر تغییر داشته‌اند.

این سنجش چه چیزی را ثابت نمی‌کند

باید صریح گفت که این چهار معیار چه چیزی را نسنجیده‌اند، چون همین‌جا بیشتر اشتباه‌ها اتفاق می‌افتد. هیچ‌کدام از این اعداد کیفیت کد را نمی‌گویند. هیچ‌کدام نمی‌گویند پروژه پاسخ می‌دهد یا نه. هیچ‌کدام به شما نمی‌گویند مجوز پروژه چیست، و در این هفت مخزن مجوزها یکسان نبودند: چهار مورد متن‌باز با شرط‌های متفاوت و یک مورد بدون مجوز شناخته‌شده. بدتر از بی‌مجوزی، مجوز هست و وابستگی زیر پای آن نیست: این هشدار امنیتی دقیقاً از شکافی می‌گوید که هر چهار معیار جدول بالا، با هم، آن را نمی‌بینند.

همچنین سرعت روزانه یک میانگین روی کل عمر است، نه سرعت همین هفته. برای مخزنی که پارسال ساخته شده این دو یکی نیستند: نرخ میانگین پایین است در حالی که سرعت همین روزها می‌تواند کاملاً متفاوت باشد. اگر به سرعت همین هفته نیاز دارید، باید اختلاف دو بردار زمانی را بگیرید، نه یک عدد را تقسیم بر سن.

یک محدودیت دیگر خود داده است. رابط برنامه‌نویسی گیت‌هاب تاریخ ستاره‌ها را نمی‌دهد، فقط شمارش لحظه‌ای را. پس محاسبه‌ی سرعت با تقسیم بر سن، یک تخمین یکنواخت است: فرض می‌کند ستاره‌ها یکنواخت پخش شده‌اند. برای مخزنی که همه‌ی ستاره‌هایش در یک هفته آمده، این تخمین به‌شدت پایین‌تر از واقعیت می‌ماند.

این سه محدودیت را کنار هم بگذارید و می‌بینید که جدول بالا یک ابزار غربال است، نه یک ابزار تصمیم. کاری که می‌کند این است که فهرست هفت‌تایی شما را به دو یا سه گزینه کاهش می‌دهد تا وقت کافی برای خواندن کد آن‌ها داشته باشید.

سه پرسشی که قبل از خواندن کد بپرسید

سه پرسش زیر ترتیب کار را کوتاه می‌کنند، و هر کدام یک دسته از این هفت مخزن را کنار می‌گذارد.

  1. آخرین تغییر چقدر دیر است؟ روزهای بی‌کاری بیش از شصت یعنی متوقف، بین ده تا شصت یعنی کند ولی زنده، و کمتر از ده یعنی فعال. این پرسش به‌تنهایی مخزنی را که ۲۴۴ روز بی‌کار بوده حذف می‌کند.
  2. نسبت فورک چقدر است؟ زیر یک درصد یعنی تقریباً هیچ استفاده‌ی واقعی نبوده. اگر دنبال چیزی برای استفاده در کار خودتان هستید، این پرسش مهم‌تر از ستاره است.
  3. مجوز چه می‌گذارد؟ مجوز بدون نام یا مجوز سازگارنشده یعنی برای کار تجاری ریسک دارد، حتی اگر هزاران ستاره داشته باشد.

اگر این سه را به‌صورت خودکار در اسکریپت خودتان بگذارید، هر مخزنی که هر سه را رد کند هرگز به فهرست شما نمی‌آید. در این هفت مورد، این فیلتر ترتیب را از هفت به پنج می‌رساند و وقت شما را روی همان‌ها می‌گذارد.

گام آخر، خواندن است، و این گام هیچ ابزاری ندارد. یک مخزن را باز کنید، فایل خواندنش را بخوانید و ببینید آیا ادعای اصلی‌اش را همان فایل ثابت می‌کند یا نه. مرجعِ سنجش، مستندات رسمی همان چیزی است که مخزن ادعایش را می‌کند؛ برای یک چارچوب زیر‌ایجنت، مرجع زیر‌ایجنت‌ها معیار است، نه فهرست امکاناتی که فایل خواندن ادعا می‌کند. در همین هفت مخزن، یکی با یک فورک و بدون سابقه‌ی ساخت قابل بررسی، بهترین نرخ روزانه‌ی جدول را دارد. هیچ عددی در جدول این را به شما نمی‌گفت.

پس روش را این‌طور خلاصه کنم: ستاره را برای تشخیص بلوغ نگه دارید، سرعت روزانه را برای تشخیص تازگی، نسبت فورک را برای تشخیص استفاده‌ی واقعی، و بی‌کاری را برای تشخیص زنده بودن. پشت سر این چهار معیار، مستندات رسمی هست که ادعای مخزن را با آن می‌سنجید: مرجع اسکیل‌ها و مرجع حافظه به شما می‌گویند چه چیزی باید در یک پیاده‌سازی درست باشد، نه اینکه چند نفر ستاره داده‌اند. هیچ‌کدام از چهار عدد به‌تنهایی کافی نیست و هیچ‌کدام جای خواندن کد را نمی‌گیرد، اما ترکیبشان فهرست هفت‌تایی را به دو گزینه تبدیل می‌کند و همین‌جاست که کار انسانی شروع می‌شود. اگر یکی از این دو گزینه از همین فهرست باشد، نصب و پروفایل‌های ECC قدم بعدی است.

منابع

  1. مخزن ECC در گیت‌هاب — همان مخزنی که هر چهار معیار روی آن خوانده شد
  2. فایل خواندن ECC — نخستین فایلی که باید باز شود، چون ادعای اصلی اینجاست
  3. تاریخچه‌ی تغییرات ECC — ریتم انتشار، جایگزین بهتری برای روزهای بی‌کاری
  4. پرونده‌ی نسخه در ECC — نشانه‌ای که یک فایل بی‌نام پروژه را لو می‌دهد
  5. راهنمای پوشه‌ی rules — جایی که محتوای واقعی مخزن جمع می‌شود
  6. متادیتای بسته در رجیستری npm — نسخه، مجوز و تاریخ انتشار، بدون نیاز به کلون کردن
  7. شمارش دانلود هفتگی — عددی که در جدول جایی ندارد و همان کار سن روز را می‌کند
  8. هشدار امنیتی منتشرشده برای یکی از وابستگی‌ها — چیزی که هیچ‌یک از چهار معیار نمی‌بیند
  9. سایت ابزار — جایی برای سنجیدن ادعای مخزن در برابر چیزی که واقعاً عرضه شده
  10. مستند رسمی اسکیل‌ها — مرجعی که ادعای یک مخزن را با آن می‌سنجید