← Назад к вопросам

Как проводишь проверку кода на качество

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 принципы соблюдаются

Качество кода — это инвестиция в будущее проекта, облегчающая поддержку и расширение функционала.