آشنایی با ابزارهای تجزیه و تحلیل کد: چگونه کیفیت کدهای اندروید را بسنجیم؟ – بخش دوم
در مطلب قبلی با ابزارهای Checkstyle و PMD آشنا شدیم و در ادامه به معرفی دو ابزار کارآمد دیگر به نام های FindBugs و Lint میپردازیم که در زمینه بررسی کدهای اندروید به کمک شما می آیند، با ما همراه باشید.
FindBugs
FindBugs یک ابزار تحلیل رایگان است که با بررسی کلاس به دنبال مشکلات بالقوه ای میگردد که با چک کردن بایت کد بر اساس لیستی از الگوهای باگ رایج صورت میپذیرد که برخی از آنها شامل موارد زیر میباشند:
کلاس به جای ()equals متد ()hashcode را تعریف کرده است: کلاس به جای متد ()equals متد ()hashCode را پیاده سازی کرده، در نتیجه ممکن است دو نمونه اولیه برابر باشند، اما کدهای هش یکسانی نداشته باشند.
مقایسه مقدار صحیح با long constant: کد یک مقدار صحیح (int) را با یک مقدار long constant مقایسه میکند که خارج از محدوده مقادیری است که میتوان در یک مقدار صحیح نمایش داد. این مقایسه بی معنی است و به نتیجه غیرمنتظره ای می انجامد.
TestCase فاقد متد تست است: کلاس یک JUnit Testcase است، اما هیچ متد تستی را پیاده سازی نکرده است.
FindBugs یک پروژه اپن سورس است و میتوانید روند رشد سورس کد را در GitHub مشاهده کنید.
میخواهیم در فایل findbugs-execute.xml، از اسکن شدن برخی کلاس ها (با استفاده از عبارت های منظم) مانند سورس و منیفست که به طور خودکار تولید شده اند جلوگیری کنیم. در صورت استفاده از Dagger نیز میخواهیم FindBugs کلاس های تولیدشده توسط Dagger را بررسی نکند، حتی میتوان به FindBugs گفت که برخی از قوانین را نادیده بگیرد.
<FindBugsFilter>
<!-- Do not check auto-generated resources classes -->
<Match>
<Class name="~.*R\$.*"/>
</Match>
<!-- Do not check auto-generated manifest classes -->
<Match>
<Class name="~.*Manifest\$.*"/>
</Match>
<!-- Do not check auto-generated classes (Dagger puts $ into class names) -->
<Match>
<Class name="~.*Dagger*.*"/>
</Match>
<!-- http://findbugs.sourceforge.net/bugDescriptions.html#ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD-->
<Match>
<Bug pattern="ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD" />
</Match>
</FindBugsFilter>
در نهایت تسک findbugs را در quality.gradle قرار میدهیم:
apply plugin: 'findbugs'
task findbugs(type: FindBugs) {
description 'Run findbugs'
group 'verification'
classes = files("$project.buildDir/intermediates/classes")
source 'src'
classpath = files()
effort 'max'
reportLevel = "high"
excludeFilter file('./code_quality_tools/findbugs-exclude.xml')
reports {
xml.enabled = false
html.enabled = true
}
ignoreFailures = false
}
در اولین خط از کد بالا، از FindBugs به عنوان Gradle Plugin استفاده کرده و سپس یک تسک به نام findbugs ساختیم. ویژگی های کلیدی تسک findbugs شامل موارد زیر میباشد:
classes: کلاس هایی که باید مورد تجزیه و تحلیل قرار گیرند
effort: میزان تحلیل ها را مشخص میکند و مقدار تعیین شده باید یک عدد min ،default یا max باشد. توجه داشته باشید که هرچه لول بالاتر باشد، دقت و احتمال یافتن باگ های بیشتر افزایش یافته، اما زمان و حافظه بیشتری مصرف میشود.
reportlevel: اولویت گزارش باگ ها را مشخص میکند. اگر مقدار آن کوچک باشد، تمامی باگ ها گزارش داده میشوند، مقدار متوسط (یا پیشفرض) باگ های متوسط و با اولویت بالا را گزارش میدهد و مقدار بالا تنها باگ هایی که اولویت بالایی دارند را گزارش میدهد.
executeFilter: نام فایل فیلتری که باگ هایی را نباید گزارش داده شوند مشخص میکند.
پس از این کار میتوانید اسکریپت Gradle را با مراجعه به پنجره ابزار Gradle مشاهده کنید، برای این کار فولدر verification group را باز کرده و برای اجرای تسک بر روی findbugs کلیک کنید یا از طریق کامند لاین آن را به اجرا درآورید:
gradle findbugs
وقتی اجرای تسک به پایان رسید، گزارشی تولید میشود که از طریق app module> build> reports> findbugs در دسترس میباشد. FindBugs plugin یکی دیگر از پلاگین های رایگان در دسترس بوده که میتوانید آن را دانلود کرده و با IntelliJ IDEA یا اندروید استودیو یکپارچه کنید.
Android Lint
Lint یکی دیگر از ابزارهای تحلیل است که به طور پیشفرض در اندروید استودیو وجود دارد. این ابزار فایل های منبع پروژه اندروید را از نظر باگ ها و بهینه سازی برای صحت، امنیت، عملکرد، کاربرد، دسترس پذیری و بین المللی بودن بررسی میکند. برای پیکربندی Lint باید بلاک {}lintOptions را در فایل سطح ماژول build.gradle قرار دهید:
lintOptions {
abortOnError false
quiet true
lintConfig file('./code_quality_tools/lint.xml')
}
تنظیمات کلیدی Lint شامل موارد زیر میباشد:
abortOnError: تعیین میکند که Lint در صورت پیدا شدن خطا از کد فرآیند خارج شود یا خیر
quiet: غیرفعال کردن فرآیند تجزیه و تحلیل
lintconfig: فایل پیکربندی پیش فرض که مورد استفاده قرار میگیرد
فایل lint.xml میتواند شامل مشکلاتی باشد که میخواهید توسط Lint نادیده گرفته شده یا تغییر داده شود، برای نمونه به مثال زیر توجه کنید:
<?xml version="1.0" encoding="UTF-8"?>
<lint>
<!-- Disable the given check in this project -->
<issue id="IconMissingDensityFolder" severity="ignore" />
<!-- Change the severity of hardcoded strings to "error" -->
<issue id="HardcodedText" severity="error" />
</lint>
شما میتوانید به صورت دستی Lint را از اندروید استودیو اجرا کنید، برای این کار باید بر روی منوی Analyze کلیک کرده و Inspect Code را بزنید و سپس بر روی دکمه OK کلیک کنید.
با مراجعه به پنجره ابزار Gradle نیز قادر به اجرای Lint هستید، verification group را باز کرده و بر روی lint کلیک کنید، امکان اجرا از طریق کامند لاین نیز وجود دارد.
در ویندوز:
gradlew lint
در لینوکس یا مک:
./gradlew lint
با اتمام اجرای تسک یک گزارش تولید میشود که از طریق app module> build> outputs> lint-results.html در دسترس است.
StrictMode
StrictMode یک ابزار توسعه دهنده است که مانع از انجام flash I/O یا network I/O تصادفی در ترد اصلی توسط توسعه دهندگان پروژه میشود، زیرا در غیراین صورت اپلیکیشن کند شده یا واکنش گرایی خود را از دست میدهد. علاوه بر این، برای جلوگیری از نمایش دیالوگ های ANR هم مفید است. با StrictMode اپلیکیشن واکنش گراتر شده و کاربران از تجربه روان تری بهره مند میشوند. StrictMode از دو روش برای اعمال قوانین خود استفاده میکند:
VM Policies: مشکلاتی مانند نبستن آبجکت های SQLiteCursor یا هر آبجکت closeable دیگر که ساخته شده است را مورد بررسی قرار میدهد.
Thread Policies: به دنبال عملیاتی مانند flash I/O یا network I/O میگردد که به جای اجرا در ترد پس زمینه، در ترد اصلی اپلیکیشن به اجرا درمی آیند.
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork() // or .detectAll() for all detectable problems
.penaltyLog() // Log detected violations to the system log.
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects()
.penaltyLog()
.penaltyDeath() // Crashes the whole process on violation.
.build());
}
کد بالا را میتوان در اپلیکیشن، اکتیویتی یا هر متد ()onCreate دیگر کامپوننت اپلیکیشن قرار داد.
برای کسب اطلاعات بیشتر درباره StrictMode میتوانید به این لینک مراجعه کنید.
برای مشاهده پروژه نمونه که تمامی قوانین بالا را پیاده سازی کرده میتوانید به GitHub repo مراجعه نمایید.
جمع بندی
در این مطلب آموزشی با ابزارهایی آشنا شدید که با استفاده از آنها میتوان از کیفیت کدهای نوشته شده اطمینان حاصل کرد. مزایای این ابزارها و نحوه استفاده از Checkstyle ،Findbugs ،Lint ،PMD و StrictMode در اپلیکیشن نیز آموزش داده شد. با استفاده از این ابزارها میتوانید مشکلات موجود در کدهای خود را شناسایی و اقدام به بهبود آنها نمایید.