← Назад к вопросам
Как проводишь проверку кода на качество
1.0 Junior🔥 111 комментариев
#Тестирование#Архитектура и паттерны
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Проверка кода на качество (Code Quality)
Проверка качества кода — это систематический процесс выявления ошибок, нарушений стиля и потенциальных проблем. В Android разработке я использую многоуровневый подход:
1. Статический анализ (Static Analysis)
Android Lint — встроенный анализатор Android Studio:
// ❌ Lint предупреждает о проблемах
class MainActivity : AppCompatActivity() {
val api = "hardcoded_secret_key" // Warning: hardcoded secret
fun loadImage() {
val imageSize = 0 // Warning: resource leak
// imageSize не закрыта
}
}
// ✅ Исправленный код
class MainActivity : AppCompatActivity() {
// Используем env переменные
private fun getApiKey() = BuildConfig.API_KEY
fun loadImage() {
val bitmap = loadBitmap()
bitmap?.recycle() // Правильно закрыли ресурс
}
}
Ktlint для стиля кода:
# Проверка кода
ktlint
# Автоисправление
ktlint -F
Detekt для архитектурных проблем:
// detekt-config.yml
detekt:
ignoreFailures: false
input:
- src
exclude:
- test
- build
2. Код ревью (Code Review)
Процесс ревью перед merge в main:
// Чек 1: Архитектура - соответствие SOLID
// ❌ Нарушение Single Responsibility
class UserManager {
fun getUser() { } // Бизнес-логика
fun saveToDB() { } // БД
fun sendToServer() { } // Сеть
fun logMessage() { } // Логирование
fun validateEmail() { } // Валидация
}
// ✅ Правильно - разделение ответственности
class UserRepository {
fun getUser(): User { } // Только БД
}
class UserService {
fun fetchAndSaveUser() { } // Бизнес-логика
}
class EmailValidator {
fun validate(email: String) { } // Только валидация
}
// Чек 2: Производительность
// ❌ Неэффективно
fun findUser(userId: Int): User? {
return users.filter { it.id == userId }.firstOrNull()
// filter создаёт новый список!
}
// ✅ Оптимально
fun findUser(userId: Int): User? {
return users.find { it.id == userId } // O(n), но без доп памяти
}
// ✅ Ещё лучше для больших данных
fun findUser(userId: Int, userMap: Map<Int, User>): User? {
return userMap[userId] // O(1)
}
// Чек 3: Memory Leaks
// ❌ Утечка памяти
class MyActivity : AppCompatActivity() {
private val handler = Handler(Looper.getMainLooper())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
handler.postDelayed({
println("Hello") // Анонимный класс держит ссылку на Activity!
}, 5000)
}
}
// ✅ Исправить
class MyActivity : AppCompatActivity() {
private val handler = Handler(Looper.getMainLooper())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
handler.postDelayed({
if (!isDestroyed) { // Проверка, жива ли Activity
println("Hello")
}
}, 5000)
}
override fun onDestroy() {
super.onDestroy()
handler.removeCallbacksAndMessages(null) // Отменить все
}
}
3. Unit тестирование
Тесты проверяют корректность логики:
class UserRepositoryTest {
private lateinit var userDao: UserDao
private lateinit var repository: UserRepository
@Before
fun setup() {
userDao = mock()
repository = UserRepository(userDao)
}
@Test
fun testGetUserReturnsCorrectUser() {
val expectedUser = User(1, "John")
`when`(userDao.getUser(1)).thenReturn(expectedUser)
val result = repository.getUser(1)
assertEquals(expectedUser, result)
verify(userDao).getUser(1)
}
@Test
fun testGetUserHandlesException() {
`when`(userDao.getUser(1)).thenThrow(Exception("DB Error"))
assertThrows<Exception> {
repository.getUser(1)
}
}
}
4. Инструменты и CI/CD
SonarQube для анализа качества:
plugins {
id 'org.sonarqube' version '3.3'
}
sonarqube {
properties {
property 'sonar.projectKey', 'my-app'
property 'sonar.host.url', 'https://sonarqube.example.com'
property 'sonar.login', 'token'
}
}
GitHub Actions для автоматизации:
name: Code Quality Check
on: [push, pull_request]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-java@v2
with:
java-version: '11'
- name: Run Lint
run: ./gradlew lint
- name: Run Tests
run: ./gradlew test
- name: Run Detekt
run: ./gradlew detekt
5. Метрики качества
Ключевые метрики, которые я отслеживаю:
// 1. Покрытие тестами (Coverage) — минимум 80%
class Calculator {
fun add(a: Int, b: Int) = a + b // Покрыто тестом ✓
fun multiply(a: Int, b: Int) = a * b // НЕ покрыто ✗
}
// 2. Cyclomatic Complexity — меньше 10
// ❌ Высокая сложность
fun complex(a: Int, b: Int, c: Int) {
if (a > 0)
if (b > 0)
if (c > 0)
if (a > b)
if (b > c)
println("Complex")
}
// ✅ Низкая сложность
fun simple(a: Int, b: Int, c: Int) {
if (a > 0 && b > 0 && c > 0 && a > b && b > c) {
println("Simple")
}
}
// 3. Code Duplication — менее 5%
// ❌ Дублирование
fun getUserById(id: Int): User {
val user = db.query("SELECT * FROM users WHERE id = ?", arrayOf(id))
println("Got user: ${user.name}")
return user
}
fun getPostById(id: Int): Post {
val post = db.query("SELECT * FROM posts WHERE id = ?", arrayOf(id))
println("Got post: ${post.title}")
return post
}
// ✅ DRY
fun <T> getById(tableName: String, id: Int): T {
val item = db.query("SELECT * FROM $tableName WHERE id = ?", arrayOf(id))
println("Got item")
return item
}
6. Checklist при ревью
- ✓ Код следует style guide (Kotlin Coding Conventions)
- ✓ Нет дублирования (DRY)
- ✓ Правильная обработка ошибок
- ✓ Нет memory leaks
- ✓ Тесты существуют и проходят
- ✓ Документированы сложные части
- ✓ Производительность приемлема
- ✓ Security best practices соблюдаются
- ✓ SOLID принципы соблюдаются
Качество кода — это инвестиция в будущее проекта, облегчающая поддержку и расширение функционала.