تصور کنید ابزاری میسازید که قرار است نقشهی دقیق یک شهر را رسم کند، اما متوجه میشوید تمام خیابانهای اصلی را نادیده گرفته و فقط کوچههای بنبست را میشناسد. این دقیقاً همان اتفاقی بود که در ۵ سپتامبر ۲۰۲۶ برای Mirofy رخ داد؛ ابزاری که برای ترسیم نمودارهای معماری کد طراحی شده اما در مواجهه با ۱۳ مخزن واقعی، ۱۳ بار به ۱۳ شکل مختلف شکست خورد. در واقع، یک ابزار واحد که برای نقشهبرداری از معماری کد طراحی شده بود، در ۱۳ مورد مختلف و به ۱۳ روش متفاوت با خطا مواجه شد.
بسیاری از توسعهدهندگان ابزارهای خود را با چند مخزن نمونه که حاوی زبان هدف هستند تست میکنند. اما سازنده Mirofy دریافت که تأیید یک آداپتور (Adapter) — شبیه به یک رابط تبدیل برق که اجازه میدهد دو دستگاه ناسازگار به هم وصل شوند — برای زبان Rust در پروژهای جاوااسکریپتی که اتفاقی مقداری کد Rust دارد، هیچ ارزشی ندارد و فقط یک خطای آماری است که چیزی را ثابت نمیکند. همانطور که در تحلیلهای پیشین ما دربارهی امنیت مدلهای بازمتن اشاره کردیم، تکیه بر دادههای غیرواقعی منجر به ایجاد نقاط کور خطرناک میشود. این شکاف در متدولوژی تست، هزاران باگ را در معرض دید، اما پنهان نگه داشته بود. این چالشها یادآور برخی باگهای بحرانی در اتصال عاملهای هوش مصنوعی به API است که نشان داد چگونه نقصهای کوچک در لایههای رابط، منجر به شکستهای سیستمی میشوند.
فلسفهٔ شکافها
برای یافتن این خطاها، توسعهدهنده قانونی سختگیرانه وضع کرد: هیچ چیزی رسم نمیشود مگر آنکه قابل استناد باشد. هر یال در خروجی باید به فایل، خط و کامیت (Commit) مشخصی اشاره کند که آن یال را توجیه میکند. اگر کاربر روی یک فلش کلیک کند، باید دقیقاً عبارت import مربوطه را ببیند.
طبق مستندات این پروژه، اگر ارجاعی در مخزن یافت نشود، ابزار آن را بهصورت خاموش حذف نمیکند یا حدس نمیزند. در عوض، آن را به عنوان یک «شکاف» (Gap) گزارش میدهد. ابزاری که موارد نامعلوم را حذف میکند، بینقص به نظر میرسد اما در عمل بیفایده است؛ در مقابل، ابزاری که شکافها را با نام و تعداد گزارش میکند، هر بار که گیج شود فریاد میزند. این شفافیت، Mirofy را به یک ماشین شکار باگ تبدیل کرد.
شکستهای Java و Kotlin
به گزارش سازنده، در زبان Java، تحلیلگر با پیشوندهای پکیج دچار سردرگمی شد. برای مثال، کتابخانه Guava با Truth اشتباه گرفته شد چون هر دو پیشوند com.google.common داشتند. به دلیل تطبیق بر اساس پیشوند، Truth شبیه به کد خودِ Guava به نظر میرسید و منجر به ۸۳۴ شکاف کاذب شد که حدود ۲۸٪ از مخزن را شامل میشد. راه حل این بود که ابزار ابتدا بررسی کند آیا بخش بعدی مسیر یک «تایپ» است یا خیر، زیرا مثلاً com.google.common.truth.Truth به یک پکیج ختم میشود در حالی که com.google.common.collect.ImmutableList به یک کلاس ختم میشود.
سایر باگهای Java و Kotlin عبارت بودند از:
- وارداتهای داخلی (Self-Imports): جاوا برای ثابتهای enum تودرتو حتی در همان فایل نیاز به import دارد. اگر این مورد به عنوان یک وابستگی در نظر گرفته شود، باعث میشود فلشهایی از یک فایل به خودش رسم شود. این موضوع منجر به ایجاد ۱۳۷ شکاف در Spring Boot و ۳۴ مورد در Guava شد.
- عمق واردات استاتیک: وارداتی مثل
static com.google.gson.Foo.BARبه یک عضو (Member) اشاره میکنند، نه یک پکیج. خواندن اینها به عنوان پکیج، ۱۰۶ مورد اشتباه ایجاد کرد که انگار gson به نسخهای منتشر شده از خودش وابسته است. تایپهای تودرتو (Nested types) نیز ۸۴ خطای مشابه دیگر اضافه کردند. - فضاهای نام مشترک: کاتلین و جاوا فضای نام مشترکی دارند. یک فایل کاتلین که یک تایپ جاوا را از همان مخزن وارد میکند، یک یال واقعی است. چون ایندکس ابتدا بر اساس پسوند فایل ساخته شده بود، ۱۱۲ یال واقعی در Spring Boot به عنوان مورد مفقود گزارش شد.
لبههای پیچیده در Rust و Go
بزرگترین شکست در Rust رخ داد. توسعهدهنده مسیر منبع را بهصورت سختافزاری روی src/ تنظیم کرده بود، اما مانیفست Deno مسیر را به صورت [lib] path = "lib.rs" تعیین کرده بود. این فرض ساده باعث ایجاد ۳۸۹۶ شکاف شد که ۲۷٪ از کل حقایق مخزن را میساخت. جالب اینجاست که چون Deno بسیار بزرگ است، اعداد کلی منطقی به نظر میرسیدند و خطا تنها با مشاهده شکل غلط نمودار، نه با خواندن تعداد شکافها، کشف شد.
سایر مسائل Rust و Go:
- تستهای یکپارچهسازی: Cargo هر فرزند مستقیم دایرکتوری
tests/را به عنوان یک crate مجزا کامپایل میکند. بنابراین عبارتcrate::utilدر یک تست یکپارچهسازی، به ابزاری اشاره دارد که در کنار تست قرار دارد، نه به ابزار اصلی کتابخانه. - ماژولهای تست داخلی: الگوی رایج
use super::*در Rust بهاشتباه به ریشه crate ارجاع داده میشد. این یک «پاسخ غلط» بود نه یک شکاف، که بدتر است چون تعداد حقایق را بهطور خاموش افزایش میدهد. - نامگذاری دایرکتوری: در Go، ابزار طوری برنامهریزی شده بود که دایرکتوریهای نامگذاری شده با
buildرا نادیده بگیرد (مشابه روشی که توسعهدهندگانnode_modulesرا نادیده میگیرند). اما پروژه Moby چهار پکیج دارد که واقعاً نامشانbuildاست و تمام ۵۳ واردات این پکیجها به عنوان شکاف گزارش شد.
شکاف اصلاحگر Kotlin
سینتکس fun interface در کاتلین (مثلاً fun interface Dns { }) در لیست اصلاحگرهای تعریف (Declaration Modifiers) وجود نداشت. این یعنی تایپهای حیاتی در OkHttp (مثل okhttp3.Dns و okhttp3.Interceptor) و LeakCanary (مثل EventListener) کاملاً از ایندکس تایپها حذف شده بودند.
علاوه بر این، ابزار تشخیص نداد که ثابتهای با فرمت SCREAMING_SNAKE (مثل USER_AGENT یا TYPE_A یا UTC) تایپ نیستند، که ۳۱ شکاف دیگر به آمار OkHttp اضافه کرد.
درسهایی در اعتبارسنجی
این تجربه معیار اعتبارسنجی ابزارهای توسعه را تغییر میدهد. توسعهدهنده ابتدا آداپتور Rust را با Next.js و آداپتور Kotlin را با Spring Boot تست کرده بود، اما هیچکدام از این پروژهها واقعاً با آن زبانها ساخته نشده بودند. وقتی ابزار روی Deno، Tokio، OkHttp و LeakCanary اجرا شد، شدیدترین نقصها ظاهر شدند.
این ثابت میکند مجموعهای از دادههای تست که در آن زبان هدف در اقلیت است، ممکن است پاس شود اما هیچ چیز را ثابت نمیکند. برای قابلاعتماد بودن یک ابزار، باید در مخازنی تست شود که آن زبان، محور اصلی پروژه باشد.
امروز Mirofy از JavaScript، TypeScript، Python، Go، Java، Rust و Kotlin پشتیبانی میکند و بهجای تکیه بر قراردادهای دایرکتوری، از اعلانهای رسمی استفاده میکند؛ مانند مسیر ماژول در go.mod ، عبارتهای package در فایلهای .java و مسیرها در Cargo.toml. در مجموع ۱۳ مخزن و ۸۵,۹۳۰ فایل، ابزار ۲۷۸,۹۸۲ حقیقت را پردازش کرد و اکنون چهار مخزن هیچ ارجاع حلنشدهای ندارند.
Mirofy تحت لایسنس MIT است و هیچ وابستگی در زمان اجرا ندارد. خروجی آن یک فایل HTML مستقل است که بدون نیاز به سرور، مستقیماً از روی دیسک باز میشود. شما میتوانید با دستور npx mirofy-cli map . نقشهی معماری کد خود را تولید کنید.
گام بعدی شما
- اگر ابزاری برای تحلیل کد میسازید، تستهای خود را از محیطهای کنترلشده به مخازن عظیم و متنوع (مثل Deno یا Spring) منتقل کنید.
- در طراحی ابزارهای تحلیل، بهجای حذف موارد نامعلوم، مکانیزم «گزارش شکاف» را پیاده کنید تا نقاط کور مدل یا کدتان آشکار شود.
- برای تحلیل سریع ساختار پروژههای Open Source، از Mirofy برای تبدیل کد به نمودار بصری استفاده کنید.
اما داستان سختافزاری این تحول حتی شگفتانگیزتر است — به تحلیل ما دربارهی تراشههای Blackwell مراجعه کنید.




گفتگو