پرش به محتوای اصلی
پرش به محتوای مقاله

آیا Avouch می‌تواند گزارش‌های تحلیل ایستا را از نویز پاک کند؟

·۲۷ مرداد ۱۴۰۵۲۳ دقیقه مطالعه۱ بازدید
بررسی تغییرات پایتون شما نه کد به ارث رسیده. بازبینی کد مبتنی بر AST و آگاه از گیت، در ثانیه‌های قبل از push.
بررسی تغییرات پایتون شما نه کد به ارث رسیده. بازبینی کد مبتنی بر AST و آگاه از گیت، در ثانیه‌های قبل از push.
اشتراک‌گذاری
واقعاً چه چیز جدید است؟

نوآوری اصلی در پیوند زدن تحلیل ایستای AST مستقیماً به Git Diff است؛ به‌جای تحلیل کل پروژه، فقط تغییرات جاری بررسی می‌شوند تا نویز گزارش‌ها حذف شود.

تصور کنید در جلسه بررسی کد، به‌جای غرق شدن در هزاران خط کد قدیمی، فقط روی همان چند خطی تمرکز کنید که خودتان تغییر داده‌اید و واقعاً مسئولیت آن‌ها را بر عهده دارید. Avouch دقیقاً همین تجربه را ممکن می‌کند؛ ابزاری که تحلیل ایستای پایتون را از کل مخزن به «تفاضل» (Diff) یک کامیت منتقل می‌کند. این ابزار با تغییر تمرکز از کل کدبیس به تغییرات خاص، اجازه می‌دهد توسعه‌دهنده فقط روی اثرات مستقیم کدهای جدیدش متمرکز شود.

این ابزار به‌عنوان یک رابط خط فرمان (CLI) سبک، از Git می‌پرسد کدام فایل‌ها در کامیت بعدی تغییر می‌کنند، آن‌ها را با ماژول استاندارد ast تحلیل می‌کند و مشکلات ساختاری را بر اساس محدودیت‌های قابل تنظیم گزارش می‌دهد. همان‌طور که در بحث‌های گذشته ما درباره‌ی مدیریت بدهی فنی در پروژه‌های متن‌باز اشاره کردیم، بزرگ‌ترین مانع پذیرش استانداردهای کدنویسی، حجم عظیم هشدارهای قدیمی است.

بسیاری از ابزارهای تحلیل ایستا دچار «نویز» هستند؛ صدها هشدار مربوط به کدهای قدیمی که خطاهای جدید برنامه‌نویس را می‌بلعند. این وضعیت یک سد روان‌شناختی ایجاد می‌کند که در آن توسعه‌دهندگان گزارش‌های Linting را نادیده می‌گیرند چون نسبت سیگنال به نویز بسیار پایین است. Avouch با محاسبه مجموعه بررسی در زمان اجرا از طریق دستور git diff HEAD --name-only به همراه فایل‌های ردیابی‌نشده (untracked)، این مشکل را حل می‌کند. طبق مستندات پروژه، هر یافته‌ای مستقیماً به کاری مربوط است که شما در حال Push کردن آن هستید، و هرگز به میراثی که از دیگران به ارث برده‌اید مربوط نمی‌شود.

مزیت تحلیل AST

برخلاف بسیاری از Linterهای سبک که بر پایه عبارت‌های منظم (Regex) هستند، Avouch از ماژول درخت نحو انتزاعی (AST) پایتون استفاده می‌کند. این رویکرد به ابزار اجازه می‌دهد ساختار واقعی کد را بفهمد؛ مثلاً می‌تواند تفاوت بین تعریف یک تابع و فراخوانی آن را تشخیص دهد، یا عمق تو در تو بودن یک بلوک را بدون فریب خوردن توسط فاصله‌ها (Indentation) یا رشته‌های چندخطی به‌طور دقیق اندازه‌گیری کند.

به نقل از مستندات فنی این پروژه، این روش ساختاری تضمین می‌کند که معیارهایی مثل تعداد پارامترها، عمق تو در تو بودن و بازه خطوط کاملاً دقیق باشند. اگر معیاری از طریق AST قابل محاسبه به‌طور دقیق نباشد، Avouch ادعایی درباره آن نمی‌کند. این دقت در نحوه مدیریت خطاها نیز جاری است: فایلی که غیرقابل خواندن باشد یا از نظر نحوی شکسته باشد، به‌عنوان یک ورودی ERROR در گزارش ثبت می‌شود، اما یک فایل خراب هرگز مانع از بررسی سایر فایل‌ها نمی‌شود.

قوانین تحلیل هسته

این ابزار با ۱۷ شناسه‌ی قانون داخلی (SCR001 تا SCR017) و دو بررسی پیچیدگی سیکلوماتیک برای توابع و کلاس‌ها عرضه شده است. تمام یافته‌های قوانین در سطح WARNING هستند و سطح ERROR فقط برای فایل‌هایی رزرو شده است که نمی‌توان آن‌ها را خواند یا تجزیه (Parse) کرد.

معیارهای پیچیدگی و منطق:

  • پیچیدگی سیکلوماتیک: توابع و کلاس‌هایی که از max_complexity (پیش‌فرض ۴۰) فراتر روند را علامت‌گذاری می‌کند. این مقدار با یک پایه ۱ شروع شده و برای هر if، for، while، try، except، match، عملگرهای سه تایی (ternary)، assert و زنجیره‌های and/or یک واحد اضافه می‌شود.
  • عمق تو در تو (SCR013): حداکثر تو در تو بودن گره‌های بلوک را که از max_nesting (پیش‌فرض ۵) بیشتر باشد شناسایی می‌کند. در اینجا if، for، while، async for، with، async with، try و match شمرده می‌شوند. توجه داشته باشید که Comprehensionها و Lambdaها عمق را افزایش نمی‌دهند.
  • پیچیدگی بولی (SCR003): زنجیره‌های تک and/or با تعداد عملوندهای بیش از حد (پیش‌فرض ۵) را هشدار می‌دهد. در زنجیره‌های تو در تو، تعداد عملوندها با هم جمع می‌شوند.
  • بوی منطقی (Logic Smells): شناسایی بلوک‌های except خالی یا «لخت» (SCR002) که باعث می‌شوند KeyboardInterrupt و SystemExit به‌طور ناخواسته گرفته شوند، و همچنین توابع async که هرگز از await استفاده نمی‌کنند (SCR001)، زیرا این توابع بدون فراهم کردن هم‌روندی، سربار حلقه رویداد (event-loop) را تحمیل می‌کنند.

محدودیت‌های ساختاری و اندازه:

  • تورم پارامترها (SCR014): توابعی با بیش از max_parameters (پیش‌فرض ۵) را شناسایی می‌کند. این قانون پارامترهای موقعیتی و کلیدواژه‌ای را می‌شمارد اما *args و **kwargs را نادیده می‌گیرد.
  • محدودیت اندازه: نظارت بر تعداد خطوط فایل (max_file_lines پیش‌فرض ۱۰۰۰)، اندازه کلاس (max_class_lines پیش‌فرض ۲۰۰) و طول تابع (max_function_lines پیش‌فرض ۳۰۰).
  • متغیرهای محلی (SCR009): توابعی که بیش از max_local_variables (پیش‌فرض ۳۰) نام متمایز را تخصیص می‌دهند. این مورد شامل ast.Assign با اهداف ast.Name می‌شود.
  • دستورات بازگشتی (SCR016): توابعی با بیش از max_return_statements (پیش‌فرض ۶) را علامت‌گذاری می‌کند.

بوی کدهای پیشرفته:

  • مقادیر پیش‌فرض تغییرپذیر (SCR017): شناسایی مقادیر پیش‌فرمی برای پارامترها که تغییرپذیر هستند، مانند [] یا {} یا فراخوانی list() و set()، که باعث نشت وضعیت (state leak) بین فراخوانی‌های مختلف تابع می‌شوند.
  • شاخه‌های تکراری (SCR004/SCR006): شناسایی شاخه‌های if/elif با بدنه‌های کاملاً یکسان. قانون SCR004 روی توابع و SCR006 روی هر دو بخش توابع و کلاس‌ها اجرا می‌شود.
  • اندازه Comprehension (SCR005): شناسایی لیست‌ها، مجموعه‌ها یا دیکشنری‌های تو در تو که از max_large_comprehensions (پیش‌فرض ۴۰) گره AST فراتر روند.
  • پیچیدگی Lambda (SCR008): بدنه‌های لمدایی که بیش از max_lambda_nodes (پیش‌فرض ۱۰) گره دارند.
  • توابع تو در تو (SCR015): شناسایی تعریف‌های ساده def در داخل توابع دیگر برای جلوگیری از ایجاد Closureهایی که تست واحد (Unit Testing) را دشوار می‌کنند.

یکپارچه‌سازی و گردش کار

Avouch برای اجرا در ثانیه‌های پیش از git push طراحی شده است. این ابزار به پایتون ۳.۱۰ به بالا (برای استفاده از ast.Match و tomllib) و وجود Git در مسیر PATH سیستم نیاز دارد. این ابزار بدون نیاز به دیمون یا اتصال شبکه کار می‌کند و زمان اجرای آن توسط اندازه Diff محدود می‌شود، نه اندازه کل مخزن.

حالت‌های بررسی:
۱. حالت پیش‌فرض: بررسی فایل‌های ردیابی‌شده که نسبت به HEAD تغییر کرده‌اند و فایل‌های .py ردیابی‌نشده. این حالت به‌طور خودکار فایل‌هایی که به نظر تولیدشده (generated) می‌رسند (مانند generated.py یا codegen.py) را نادیده می‌گیرد.
۲. حالت Staged: تحلیل فقط فایل‌هایی که برای کامیت بعدی Stage شده‌اند با استفاده از دستور git diff --cached --name-only (--staged).
۳. حالت CI: اسکن کامل مخزن (--all-files) که برای CI Runnerها (مانند GitHub Actions) ضروری است، زیرا در آنجا Checkout تمیز است و git diff HEAD مجموعه خالی برمی‌گرداند.
۴. حالت غیر Git: بررسی تمام فایل‌های .py واجد شرایط روی دیسک با پیمایش دایرکتوری جاری و نادیده گرفتن پوشه‌های .git، کش و محیط‌های مجازی (--not-git).

برای اتوماسیون، پرچم --json یک خروجی استاندارد، نسخه‌بندی شده و پایدار ارائه می‌دهد. هر تخلف شامل شناسه‌ی قانون، شدت، پیام، فایل، نام کامپوننت، نوع (func یا class یا file) و شماره خط است.

کدهای خروجی (Exit Codes) برای سیگنال‌دهی به نتایج استفاده می‌شوند:

  • ۰: بررسی پاک و بدون تخلف.
  • ۱: یافتن تخلفات.
  • ۲: خطای داخلی Avouch (مثلاً عدم یافتن مخزن Git یا پیکربندی نامعتبر).

در GitHub Actions، این ابزار با actions/checkout@v6 و actions/setup-python@v5 با پایتون ۳.۱۲ به راحتی ادغام می‌شود. دستور پیشنهادی برای CI عبارت است از avouch --all-files --json. از آنجا که GitHub Actions هر کد خروجی غیرصفر را به عنوان شکست Job تلقی می‌کند، هرگونه تخلف گزارش‌شده باعث توقف خط لوله می‌شود، مگر اینکه مسیرها در ignore_paths در فایل avouch.toml نادیده گرفته شوند.

پیکربندی و شخصی‌سازی

تنظیمات اختیاری، جزئی و توصیفی هستند و از طریق یک فایل محلی avouch.toml در دایرکتوری کاری جاری مدیریت می‌شوند. Avouch دایرکتوری‌های والد را جست‌وجو نمی‌کند تا تضمین شود پیکربندی‌ها کاملاً محلی به هر مخزن هستند.

کاربران می‌توانند تنظیمات خود را بر روی مقادیر پیش‌فرض اعمال کنند:

  • [limits]: آستانه‌های عددی قابل تغییر هستند. برای مثال، تنظیم max_parameters = 8 اجازه امضاهای منعطف‌تری را می‌دهد.
  • [rules]: قوانین را می‌توان خاموش کرد. تنظیم nested_function = false گزارش‌های SCR015 را متوقف می‌کند.
  • ignore_paths: یک لیست در سطح بالا (مثلاً ignore_paths = ["tests", "migrations"]) که مسیرها را به‌صورت کامپوننت حذف می‌کند. این لیست با پرچم --ignore-path در CLI ترکیب می‌شود.

معماری داخلی

کدبیس برای کمترین سربار طراحی شده است. ارکستراتور cli.py خط لوله را مدیریت می‌کند: بارگذاری تنظیمات توسط config/loader.py، محاسبه مجموعه بررسی توسط git.py و تحلیل فایل‌ها توسط analyzer.py. فرآیند تحلیل، فایل‌های UTF-8 را خوانده، آن‌ها را به AST تبدیل کرده و با استفاده از یک پیمایش کش‌شده (utility/walk.py) گره‌ها را به ماژول‌های قوانین در rules/*.py می‌فرستد.

تحلیل تحریریه

Avouch نشان‌دهنده تغییری به سمت تجربه توسعه‌دهنده «جراحی‌شده» (Surgical) است. با گره زدن تحلیل ایستا مستقیماً به Git Diff، اثر «پنجره شکسته» را از بین می‌برد؛ وضعیتی که در آن توسعه‌دهندگان هشدارها را نادیده می‌گیرند چون کدبیس از قبل به‌هم‌ریخته است. این ابزار Linter را از یک حسابرس جهانی به یک دستیار شخصی تبدیل می‌کند که فقط زمانی صحبت می‌کند که شما یک مشکل جدید ایجاد کرده باشید.

برای تیم‌های پایتون، این رویکرد اصطکاک پذیرش استانداردهای سخت‌گیرانه کدنویسی را کاهش می‌دهد. به‌جای وظیفه دلهره‌آور اصلاح ۵۰۰۰ هشدار قدیمی، توسعه‌دهندگان فقط باید مطمئن شوند که PR فعلی آن‌ها پاک است. این استراتژی بهبود تدریجی برای پروژه‌های سازمانی در مقیاس بزرگ، بسیار پایدارتر از تلاش برای بازنگری کلی کدبیس است. در همین راستا، تلاش برای بهینه‌سازی زیرساخت‌های توسعه با استفاده از ابزارهای تخصصی‌تر، مانند آنچه در کاهش هزینه‌های بازگردانی وضعیت فایل‌سیستم توسط Shepherd دیدیم، می‌تواند بهره‌وری کلی تیم را افزایش دهد.

برای شروع، می‌توانید ابزار را با دستور pip install avouch نصب کنید و در هر مخزن Git اجرا کنید تا دقیقاً ببینید چه بدهی ساختاری را در حال Push کردن هستید.

  • ابزار را نصب کنید و در یک مخزن Git فعال اجرا کنید تا بدهی‌های ساختاری فعلی خود را ببینید.
  • یک فایل avouch.toml ایجاد کنید و محدودیت‌های max_complexity را متناسب با استانداردهای تیم خود تنظیم کنید.
  • این ابزار را به Pre-commit hookهای خود اضافه کنید تا هیچ کد با پیچیدگی غیرمجاز Push نشود.

اما برای کسانی که به دنبال تحلیل‌های عمیق‌تر در سطح معماری هستند، ابزارهای مبتنی بر گراف کد (Code Graph) ابعاد جدیدی را می‌گشایند — به بررسی ما درباره تحلیل‌های استاتیک پیشرفته مراجعه کنید. این مسیر تکامل ابزارهای تحلیل، ما را به سمت استفاده از عامل‌های کدنویسی هوشمندتر می‌برد، مشابه رویکرد عامل Ante در کاهش مصرف حافظه که استقلال توسعه‌دهنده از ابزارهای متمرکز را هدف قرار داده است.

چرا این موضوع مهم است؟

این ابزار با کاهش نویز در بررسی کد، سرعت چرخه Review را افزایش داده و مانع از انباشت بدهی فنی جدید می‌شود. اعتبار این رویکرد در استفاده از AST به‌جای Regex است که دقت تحلیل را به سطح ساختاری می‌برد.

تأثیر برای ایران

برای تیم‌های توسعه پایتون در ایران که با پروژه‌های قدیمی (Legacy) سر و کار دارند، این ابزار راهکاری سریع برای بهبود کیفیت کد بدون نیاز به بازنویسی کل پروژه است.

·نگاه ما
تحریریه دات‌هوش

Avouch با تغییر رویکرد از «حسابر کلی» به «دستیار شخصی»، روانشناسی توسعه‌دهنده را هدف قرار داده است. این ابزار اثر «پنجره شکسته» را در کدنویسی می‌زند؛ یعنی وقتی کد کثیف است، برنامه‌نویس ترسی از اضافه کردن کثیفی جدید ندارد. با محدود کردن هشدارها به Diff، این ابزار استانداردهای سخت‌گیرانه را بدون ایجاد فرسودگی در تیم‌های بزرگ عملیاتی می‌کند.

منابع

این گزارش با خط‌لولهٔ خودکار دات‌هوش از منابع معتبر جهانی تدوین و زیر نظر تحریریه منتشر شده است. روش کار ما

گفتگو

پنج‌شنبه‌های هوش‌محور

بسته‌ی هفتگی دات‌هوش

۵ خبر، ۲ ابزار، ۱ پرامپت در هر شماره. به‌زودی راه‌اندازی می‌شود — هر پنج‌شنبه صبح.

خبر کلیدی
ابزار کاربردی
پرامپت حرفه‌ای
تحلیل پژوهش
به‌زودی
زاویه‌ی ایرانی
به‌زودی
تمرین این هفته
به‌زودی

راهنماهای دات‌هوش

راهنماهای کاربردیِ دات‌هوش برای کار با هوش مصنوعی — از همین‌جا شروع کنید:

دات‌هوش

راهنمای فارسی هوش مصنوعی — با نگاه به ایران

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