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

Назови примеры качественного кода

2.3 Middle🔥 112 комментариев
#Архитектура и паттерны#Опыт и софт-скиллы

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Примеры качественного кода для Android-разработчика

Качественный код — это не просто работающий код, а читаемый, поддерживаемый, тестируемый и эффективный код. Вот ключевые примеры и принципы, которые я применяю за 10+ лет разработки под Android.

1. Читаемость и ясность

Код должен быть понятен другим разработчикам (и вам через полгода) без лишних комментариев.

Пример плохого кода:

fun p(u: User) {
    if (u.a > 18 && u.s == "active") {
        // ... 20 строк логики
    }
}

Пример качественного кода:

fun processUserIfEligible(user: User) {
    val isAdult = user.age > MIN_ADULT_AGE
    val isActive = user.status == UserStatus.ACTIVE
    
    if (isAdult && isActive) {
        processEligibleUser(user)
    }
}

private fun processEligibleUser(user: User) {
    // Четкая, выделенная логика
    validateUserData(user)
    prepareUserForProcessing(user)
    executeUserProcessing(user)
}

2. Соблюдение принципов SOLID

Особенно Single Responsibility и Dependency Inversion.

Пример качественной архитектуры:

// Вместо монолитного класса
interface UserRepository {
    suspend fun getUserById(id: String): User
}

class UserRepositoryImpl @Inject constructor(
    private val localDataSource: UserLocalDataSource,
    private val remoteDataSource: UserRemoteDataSource,
    private val dispatcher: CoroutineDispatcher = Dispatchers.IO
) : UserRepository {
    
    override suspend fun getUserById(id: String): User {
        return withContext(dispatcher) {
            val localUser = localDataSource.getUserById(id)
            if (localUser != null) {
                return@withContext localUser
            }
            
            val remoteUser = remoteDataSource.getUserById(id)
            localDataSource.saveUser(remoteUser)
            remoteUser
        }
    }
}

3. Эффективное использование Kotlin

Использование возможностей языка для написания безопасного и выразительного кода.

Качественный пример с sealed классами и extension-функциями:

sealed class Result<out T> {
    data class Success<T>(val data: T) : Result<T>()
    data class Error(val exception: Exception) : Result<Nothing>()
    object Loading : Result<Nothing>()
}

// Extension для удобной обработки
fun <T> Result<T>.onSuccess(action: (T) -> Unit): Result<T> {
    if (this is Result.Success) {
        action(data)
    }
    return this
}

// Использование в ViewModel
class UserViewModel @Inject constructor(
    private val userRepository: UserRepository
) : ViewModel() {
    
    private val _userState = MutableStateFlow<Result<User>>(Result.Loading)
    val userState: StateFlow<Result<User>> = _userState
    
    fun loadUser(userId: String) {
        viewModelScope.launch {
            _userState.value = Result.Loading
            _userState.value = try {
                Result.Success(userRepository.getUserById(userId))
            } catch (e: Exception) {
                Result.Error(e)
            }
        }
    }
}

4. Корректная работа с асинхронностью

Использование Coroutines вместо callback hell.

Качественный пример обработки нескольких асинхронных операций:

class OrderProcessor @Inject constructor(
    private val inventoryService: InventoryService,
    private val paymentService: PaymentService,
    private val shippingService: ShippingService
) {
    suspend fun processOrder(order: Order): ProcessingResult {
        return coroutineScope {
            // Параллельное выполнение независимых операций
            val inventoryDeferred = async { inventoryService.reserveItems(order.items) }
            val paymentDeferred = async { paymentService.processPayment(order.payment) }
            
            val inventoryResult = inventoryDeferred.await()
            val paymentResult = paymentDeferred.await()
            
            if (inventoryResult.isSuccess && paymentResult.isSuccess) {
                val shippingResult = shippingService.scheduleDelivery(order)
                ProcessingResult.Success(shippingResult.trackingId)
            } else {
                // Компенсирующие транзакции при ошибке
                if (inventoryResult.isSuccess) {
                    async { inventoryService.releaseItems(order.items) }
                }
                ProcessingResult.Failure(listOf(inventoryResult.error, paymentResult.error))
            }
        }
    }
}

5. Тестируемость

Код, который легко покрывать unit-тестами.

Пример тестируемого Presenter/ViewModel:

class LoginPresenter(
    private val authRepository: AuthRepository,
    private val validator: EmailValidator,
    private val dispatcher: CoroutineDispatcher = Dispatchers.Main
) {
    
    suspend fun login(email: String, password: String): LoginResult {
        return withContext(dispatcher) {
            if (!validator.isValid(email)) {
                return@withContext LoginResult.InvalidEmail
            }
            
            try {
                val user = authRepository.authenticate(email, password)
                LoginResult.Success(user)
            } catch (e: AuthException) {
                LoginResult.Error(e.message ?: "Authentication failed")
            }
        }
    }
}

// Соответствующий тест
@Test
fun `login with invalid email returns InvalidEmail`() = runTest {
    // Arrange
    val mockValidator = mock<EmailValidator> {
        on { isValid(anyString()) } doReturn false
    }
    val presenter = LoginPresenter(mock(), mockValidator, UnconfinedTestDispatcher())
    
    // Act
    val result = presenter.login("invalid-email", "password")
    
    // Assert
    assertTrue(result is LoginResult.InvalidEmail)
}

6. Безопасность и обработка ошибок

Пример качественной обработки edge cases:

class ImageLoader @Inject constructor(
    private val cache: LruCache<String, Bitmap>,
    private val networkClient: NetworkClient,
    private val bitmapDecoder: BitmapDecoder
) {
    
    suspend fun loadImage(url: String, maxSize: Size): Result<Bitmap> {
        return try {
            // Проверка кэша
            cache.get(url)?.let { cachedBitmap ->
                return Result.success(scaleBitmap(cachedBitmap, maxSize))
            }
            
            // Загрузка с сети с таймаутом
            val imageData = withTimeout(IMAGE_LOAD_TIMEOUT) {
                networkClient.downloadImage(url)
            }
            
            // Декодирование с обработкой памяти
            val options = BitmapFactory.Options().apply {
                inJustDecodeBounds = true
                bitmapDecoder.decode(imageData, this)
                inSampleSize = calculateInSampleSize(this, maxSize)
                inJustDecodeBounds = false
            }
            
            val bitmap = bitmapDecoder.decode(imageData, options)
                ?: return Result.failure(DecodingException("Failed to decode bitmap"))
            
            // Кэширование с учетом ограничений
            if (bitmap.allocationByteCount < MAX_CACHE_ITEM_SIZE) {
                cache.put(url, bitmap)
            }
            
            Result.success(bitmap)
        } catch (e: TimeoutCancellationException) {
            Result.failure(NetworkTimeoutException("Image loading timeout", e))
        } catch (e: IOException) {
            Result.failure(NetworkException("Network error", e))
        } catch (e: Exception) {
            Result.failure(ImageLoadingException("Unexpected error", e))
        }
    }
}

7. Соблюдение Android Best Practices

Пример работы с Lifecycle:

class LocationManager(
    private val context: Context,
    private val lifecycleOwner: LifecycleOwner
) : DefaultLifecycleObserver {
    
    private val fusedLocationClient = LocationServices.getFusedLocationProviderClient(context)
    private var locationCallback: LocationCallback? = null
    
    init {
        lifecycleOwner.lifecycle.addObserver(this)
    }
    
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun startLocationUpdates() {
        val request = LocationRequest.create().apply {
            interval = LOCATION_UPDATE_INTERVAL
            priority = LocationRequest.PRIORITY_HIGH_ACCURACY
        }
        
        locationCallback = object : LocationCallback() {
            override fun onLocationResult(result: LocationResult) {
                handleNewLocation(result.lastLocation)
            }
        }
        
        fusedLocationClient.requestLocationUpdates(
            request,
            locationCallback!!,
            Looper.getMainLooper()
        )
    }
    
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun stopLocationUpdates() {
        locationCallback?.let {
            fusedLocationClient.removeLocationUpdates(it)
            locationCallback = null
        }
    }
    
    override fun onDestroy(owner: LifecycleOwner) {
        lifecycleOwner.lifecycle.removeObserver(this)
        stopLocationUpdates()
    }
}

Ключевые характеристики качественного кода:

  • Самодокументируемость — имена переменных и функций ясно отражают их назначение
  • Низкая связанность — компоненты минимально зависят друг от друга
  • Высокая связность — каждый класс/метод выполняет одну четкую задачу
  • Защита от null — использование Kotlin null-safety, Optional типов
  • Правильное использование архитектурных компонентов — ViewModel, LiveData/Flow, Repository
  • Энергоэффективность — правильная работа с фоновыми задачами, воркерами
  • Безопасность — хранение чувствительных данных в EncryptedSharedPreferences, использование Security Crypto

Качественный код требует больше времени на написание, но экономит в десятки раз больше времени на поддержку, рефакторинг и добавление нового функционала. Он делает код базой для развития, а не препятствием для изменений.