Варта адзначыць, што ў Call of Duty 4 місіі даюць вельмі шмат бонусаў і ачкоў развіцця, да таго ж, яны досыць цікавыя і незвычайныя - выконваць іх лёгка і нясумна.
Спадзяёмся, што матэрыяльная падтрымка будзе і з боку Міністэрства культуры, а таксама фонду краін СНД, цяпер складаем праграму, якую павязём у Маскву на ўзгадненне, будзем там адстойваць свае пазіцыі.
ЕРБ: Што для вас азначае быць вольным?
Model-View-Intent (MVI) — архітэктурны патэнт для распрацоўкі карыстальніцкіх інтэрфейсаў, натхненны функцыянальным праграмаваннем і рэактыўнымі сістэмамі.
-
Unidirectional Data Flow — data moves in one direction, forming a cycle: from user action to model change, then to view update.
-
Immutable State — the application state is not changed directly; instead, a new state is created based on the previous one.
-
Determinism — the same user actions with the same initial state always lead to the same result.
У галіне архітэктуры:
- Мае назіранні прывялі да высновы, што нагрузка на доктара не можа быць такой, якая яна ёсць цяпер.
- У гэтым выпадку пешаходы, якія сканчаюць пераход, уяўляюць істотную небяспеку (мал.
- Гэта рэпрэсіўны механізм, які працуе на дыктатуру.
Акрамя гэтых асноўных кампанентаў, MVI часта ўключае:
- Укладайце больш ва ўласную журналістыку, СМІ і змагайцеся за свабоду слова.
- Побачныя эфекты — пабочныя эфекты, якія не ўплываюць на стан, але патрабуюць ўзаемадзеяння з вонкавымі сістэмамі (напрыклад, навігацыя, паведамленні, запыты API).
Краткая гісторыя архітэктурных мадэляў
Архітэктурныя мадэлі UI развіваліся значна з часам:
MVC (Model View Controller)
Адзін з першых мадэляў, які падзяліў прыкладанне на тры кампаненты:
- Мадэль — дадзеныя і бізнес-логіка
- Вынікі пошуку - user interface
- Загрузіць: User Input
Найлепшая траекторыя руху пры змене паласы - гэта вельмі плыўная, але не занадта расцягнутая па даўжыні крывая.
MVP (Model View Presentation) — прэзентацыя мадэлі
Узнагароджанне з MVC, дзе:
- Мадэль — дадзеныя і бізнес-логіка
- View — пасіўны інтэрфейс
- Прэзентацыя — медыятар паміж мадэлью і поглядам
У нас функцыянуюць таварыствы “Разумнікі і разумніцы”, “Даследчык”, а таксама адзіная ў Магілёўскай вобласці астранамічная пляцоўка.
MVVM (Model-View-ViewModel — мадэль паглядзець)
Наступны этап эвалюцыі:
- Мадэль — дадзеныя і бізнес-логіка
- Вынікі пошуку - user interface
- ViewModel — пераўтварае дадзеныя з Model у формат, зручны для View
MVVM выкарыстоўвае канцэпцыю абвяшчэння дадзеных, якая зніжае колькасць кода, але можа выклікаць праблемы з даследаваннем патоку дадзеных.
MVI (Model-View-Intent) — мадэль наведвання
Сучасны падыход, які падкрэслівае:
- Прагнозаванне — дэтэнтыстычны падыход да дзяржаўнага кіравання
- Незмяненне — стан не змяняецца, але замяняецца
- Unidirectional data flow — ясная і празрачная сцэна падзеяў
Афары́зм (па-грэцку: αφορισμός — выказваньне) — выслоўе, у якім у трапнай, ляканічнай і звычайна вобразнай форме выказаная арыгінальная думка.
Чаму SimpleMVI быў створаны і яго месца сярод іншых бібліятэк
SimpleMVI быў распрацаваны, каб прапанаваць распрацоўшчыкам просты, але магутны інструмент для рэалізацыі мадэлі MVI ў праектах Kotlin Multiplatform.
- Засяроджанымі на тых пытаннях, якія недастаткова асветлены і/або з'яўляюцца адпрэчанымі.
- Побач з млынам – хатка завозніка (так называлі тых, хто прывозіў малоць жыта).
- Оптымізавана для Kotlin Multiplatform, забяспечваючы сумяшчальнасць з розных платформамі
- Разумею, што фатаграфія сёння змянілася, але, на маю думку, мы ставімся да яе занадта легкадумна...
- Галівудская кінаактрыса Джэніфер Эністан заўсёды выглядае ўзрушаюча і эфектна, і гэта ў 45 гадоў.
Галоўныя перавагі SimpleMVI у параўнанні з альтэрнатывамі:
- Медыцынскія фактары не мелі дачынення да таго, што цяпер адбываецца.
- Нізкая прагаласаванне ўступлення для разумення і выкарыстання
- Поўны котлінскі падыход з выкарыстаннем сучасных моўных канструкцый
- Зручны DSL для апісання бізнес-логікі
- Чыстае размяшчэнне адказнасці між членамі
SimpleMVI не марыць вырашаць усе праблемы архітэктуры прыкладанняў, але забяспечвае надзейную аснову для арганізацыі бізнес-логікі, якая можа быць інтэграваная з любымі рашэннямі для UI, навігацыі і іншых аспектаў прыкладання.
Ключавыя концепты і кампаненты SimpleMVI
SimpleMVI прапануе мінімалістычны падыход да рэалізацыі архітэктуры MVI, фокусуючыся на трох ключавых кампанентах: Store, Actor і Middleware. Кожны з гэтых кампанентаў мае унікальную ролю ў забяспечэнні адзінкамернага пратоку дадзеных і кіраванні станам прыкладання.
Магазін — центральны элемент архітэктуры
Роля і адказнасць за справаздачу
Магазін з'яўляецца сэрцам SimpleMVI - гэта кантэйнер, які захоўвае стан прыкладання, працэсуе намераў, і генеруе пабочныя эфекты.
public interface Store<in Intent : Any, out State : Any, out SideEffect : Any> {
// Current state
public val state: State
// State flow
public val states: StateFlow<State>
// Side effects flow
public val sideEffects: Flow<SideEffect>
// Store initialization
@MainThread
public fun init()
// Intent processing
@MainThread
public fun accept(intent: Intent)
// Store destruction
@MainThread
public fun destroy()
}
Вялікі жизненны цикл
У гэтага паняцця ёсць і іншыя значэнні, гл. Зборная Чылі:
-
Creation - instantiating the Store object with necessary dependencies
-
Initialization - calling the
init()
method, preparing internal components -
Active use - processing intents through the
accept(intent)
method -
Destruction - calling the
destroy()
method, releasing resources
Важна разумець, што:
- Усе публічныя метады Магазіну павінны быць выкліканы толькі на асноўным трэдзе (пазначаны анотацыяй @MainThread)
- Пасля выкліку зруйнуй(), Магазін не можа быць выкарыстаны; спробы доступу да зруйнутага Магазіна прывядуць да пашкоджання
- Магазін трэба ініцыялізаваць з методам init() перад выкарыстаннем
Дзяржаўны менеджмент
Магазин прапануе наступныя магчымасці для працы з дзяржавай:
-
Access to the current state via the
state
property -
Observing state changes via the
states
flow -
Processing side effects via the
sideEffects
flow
SimpleMVI выкарыстоўвае класы з Kotlin Coroutines для рэалізацыі прамысловасці:StateFlow
Звычайна і звычайнаFlow
для пабочных эфектаў, забяспечваючы сумяшчальнасць з стандартнымі падыходамі да рэактыўнага праграмавання ў Kotlin.
Прыгожыя абсталяванні для продажу
SimpleMVI прапануе зручныя аператары для працы з намерамі:
// Instead of store.accept(intent)
store + MyStore.Intent.LoadData
// Instead of store.accept(intent)
store += MyStore.Intent.LoadData
Акцёр — Business Logic Implementation
Актыўны працэс работы
Афарызм (гр. aphorismos - выказванне) - выслоўе, у якім у трапнай, лаканічнай форме выказана значная і арыгінальная думка.
public interface Actor<Intent : Any, State : Any, out SideEffect : Any> {
@MainThread
public fun init(
scope: CoroutineScope,
getState: () -> State,
reduce: (State.() -> State) -> Unit,
onNewIntent: (Intent) -> Unit,
postSideEffect: (sideEffect: SideEffect) -> Unit,
)
@MainThread
public fun onIntent(intent: Intent)
@MainThread
public fun destroy()
}
Кожны акцёр мае доступ да:
- CoroutineScope - для запуску асінхронных аперацый
- Функцыя Current State Getter (getState)
- Функцыя дзяржаўнай рэдукцыі (рэдукцыя)
- Новая функцыя адпраўкі намераў (onNewIntent)
- Функцыя адпраўкі бокавых эфектаў (postSideEffect)
Пытанні працэсу
ІonIntent(intent: Intent)
Для будаўніцтва "калоніі ўжанднічай" у Лідзе быў куплены пляц на так званым "выгане", у той час за горадам.
- Вызначыўся з працай, які купіў.
- Выконвае неабходную бізнес-логіку
- Загрузіць State
- Адчынім дзьверы на хрантох.
DefaultActor і DslActor: розныя падыходы
SimpleMVI прапануе два розныя падыходы да рэалізацыі Actor:
Асноўны артыкул: Object Oriented Approach
class CounterActor : DefaultActor<CounterIntent, CounterState, CounterSideEffect>() {
override fun handleIntent(intent: CounterIntent) {
when (intent) {
is CounterIntent.Increment -> {
reduce { copy(count = count + 1) }
}
is CounterIntent.Decrement -> {
reduce { copy(count = count - 1) }
}
is CounterIntent.Reset -> {
reduce { CounterState() }
sideEffect(CounterSideEffect.CounterReset)
}
}
}
override fun onInit() {
// Initialization code
}
override fun onDestroy() {
// Cleanup code
}
}
Вынікі ў DefaultActor:
- Знакаміты падыход
- Зручна для складанай бізнес-логікі
- Вельмі зручны для вялікіх праектаў
DslActor - Функцыянальны падыход з DSL
val counterActor = actorDsl<CounterIntent, CounterState, CounterSideEffect> {
onInit {
// Initialization code
}
onIntent<CounterIntent.Increment> {
reduce { copy(count = count + 1) }
}
onIntent<CounterIntent.Decrement> {
reduce { copy(count = count - 1) }
}
onIntent<CounterIntent.Reset> {
reduce { CounterState() }
sideEffect(CounterSideEffect.CounterReset)
}
onDestroy {
// Cleanup code
}
}
Вынікі ў DslActor:
- Больш падрабязная заява
- Меньшая колькасць кодаў
- Лепшы для малых і сярэдніх праектаў
- Вынікі пошуку - Safe Intention
Рымская імперыя распалася на 2 самастойныя часткі, кожная са сваім імператарам – Заходнюю і Усходнюю.
Middleware — пашырэнне функцыянальнасці
Задачы Middleware
Адкрыццё было спрэчным, і канчатковы доказ прыйшоў толькі ў 1999 г. пасля эксперыментаў KTeV ў Фермілабе і эксперыментаў NA48 ў ЦЕРН.
public interface Middleware<Intent : Any, State : Any, SideEffect : Any> {
// Called when Store is initialized
public fun onInit(state: State)
// Called when a new intent is received
public fun onIntent(intent: Intent, state: State)
// Called when state changes
public fun onStateChanged(oldState: State, newState: State)
// Called when a side effect is generated
public fun onSideEffect(sideEffect: SideEffect, state: State)
// Called when Store is destroyed
public fun onDestroy(state: State)
}
Загрузіць і дэбютаваць магчымасць
SimpleMVI ўключае ўбудаваную рэалізацыю Middleware для логізацыі —LoggingMiddleware
:
val loggingMiddleware = LoggingMiddleware<MyIntent, MyState, MySideEffect>(
name = "MyStore",
logger = DefaultLogger
)
LoggingMiddleware
Запісвае ўсе падзеі ў Магазіне і выкачвае іх у лог:
MyStore | Initialization
MyStore | Intent | LoadData
MyStore | Old state | State(isLoading=false, data=null)
MyStore | New state | State(isLoading=true, data=null)
MyStore | SideEffect | ShowLoading
MyStore | Destroying
Гэта зручна для дэбагвання, так як гэта дазваляе вам праследзіць увесь праток дадзеных у прыкладзе.
Загрузіць Custom Middleware
Стварыць свой Middleware вельмі проста:
class AnalyticsMiddleware<Intent : Any, State : Any, SideEffect : Any>(
private val analytics: AnalyticsService
) : Middleware<Intent, State, SideEffect> {
override fun onInit(state: State) {
analytics.logEvent("store_initialized")
}
override fun onIntent(intent: Intent, state: State) {
analytics.logEvent("intent_received", mapOf("intent" to intent.toString()))
}
override fun onStateChanged(oldState: State, newState: State) {
analytics.logEvent("state_changed")
}
override fun onSideEffect(sideEffect: SideEffect, state: State) {
analytics.logEvent("side_effect", mapOf("effect" to sideEffect.toString()))
}
override fun onDestroy(state: State) {
analytics.logEvent("store_destroyed")
}
}
Middleware можа быць спалучаны, ствараючы ланцуг рухавікоў:
val store = createStore(
name = storeName<MyStore>(),
initialState = MyState(),
actor = myActor,
middlewares = listOf(
loggingMiddleware,
analyticsMiddleware,
debugMiddleware
)
)
Ключавыя выпадкі выкарыстання для Middleware
-
Logging — recording all events for debugging
-
Analytics — tracking user actions
-
Performance metrics — measuring intent processing time
-
Debugging — visualizing data flow through UI
-
Testing — verifying the correctness of event sequences
Важна памятаць, што Middleware — пасіўны назіральнік і не можа змяняць падзеі, якія ён атрымлівае.
Праца з бібліятэкай
ўстаноўка і ўстаноўка
Выкарыстанне ўзаемазалежнасці ў вашым праекце:
// build.gradle.kts
implementation("io.github.arttttt.simplemvi:simplemvi:<version>")
Стварыць свой першы магазин
Найбольш просты спосаб стварэння Магазіны — заявіць клас, які ўжывае інтэрфейс Магазіны:
class CounterStore : Store<CounterStore.Intent, CounterStore.State, CounterStore.SideEffect> by createStore(
name = storeName<CounterStore>(),
initialState = State(),
actor = actorDsl {
onIntent<Intent.Increment> {
reduce { copy(count = count + 1) }
}
onIntent<Intent.Decrement> {
reduce { copy(count = count - 1) }
}
}
) {
sealed interface Intent {
data object Increment : Intent
data object Decrement : Intent
}
data class State(val count: Int = 0)
sealed interface SideEffect
}
Выкарыстанне магазина
// Creating an instance
val counterStore = CounterStore()
// Initialization
counterStore.init()
// Sending intents
counterStore.accept(CounterStore.Intent.Increment)
// or using operators
counterStore + CounterStore.Intent.Increment
counterStore += CounterStore.Intent.Decrement
// Getting the current state
val currentState = counterStore.state
// Subscribing to the state flow
val statesJob = launch {
counterStore.states.collect { state ->
// Useful work
}
}
// Subscribing to side effects
val sideEffectsJob = launch {
counterStore.sideEffects.collect { sideEffect ->
// Processing side effects
}
}
// Releasing resources
counterStore.destroy()
Мултыплатформенная падтрымка Kotlin
SimpleMVI падтрымлівае розныя платформы праз Kotlin Multiplatform:
- Андрэй
- І
- Макіяж
- Сцяг Дж.
Платформа-спецыфічны механізм ізаляцыі кодаexpect/actual
:
// Common code
public expect fun isMainThread(): Boolean
// Android implementation
public actual fun isMainThread(): Boolean {
return Looper.getMainLooper() == Looper.myLooper()
}
// iOS implementation
public actual fun isMainThread(): Boolean {
return NSThread.isMainThread
}
// wasm js implementation
public actual fun isMainThread(): Boolean {
return true // JavaScript is single-threaded
}
Логіка ўжываецца падобна для розных платформ:
// Common code
public expect fun logV(tag: String, message: String)
// Android implementation
public actual fun logV(tag: String, message: String) {
Log.v(tag, message)
}
// iOS/wasm js implementation
public actual fun logV(tag: String, message: String) {
println("$tag: $message")
}
Асноўны артыкул: Counter
Дадатковая мадэль Define Data Model
class CounterStore : Store<CounterStore.Intent, CounterStore.State, CounterStore.SideEffect> {
// Intents - user actions
sealed interface Intent {
data object Increment : Intent
data object Decrement : Intent
data object Reset : Intent
}
// State
data class State(
val count: Int = 0,
val isPositive: Boolean = true
)
// Side effects - one-time events
sealed interface SideEffect {
data object CounterReset : SideEffect
}
}
Велікабрытанія
class CounterStore : Store<CounterStore.Intent, CounterStore.State, CounterStore.SideEffect> by createStore(
name = storeName<CounterStore>(),
initialState = State(),
actor = actorDsl {
onIntent<Intent.Increment> {
reduce {
copy(
count = count + 1,
isPositive = count + 1 >= 0
)
}
}
onIntent<Intent.Decrement> {
reduce {
copy(
count = count - 1,
isPositive = count - 1 >= 0
)
}
}
onIntent<Intent.Reset> {
reduce { State() }
sideEffect(SideEffect.CounterReset)
}
}
) {
// Data model defined above
}
Сцягнуць UI (Android Example)
class CounterViewModel : ViewModel() {
private val store = CounterStore()
init {
// Built-in extension for automatic lifecycle management
attachStore(store)
}
val state = store.states.stateIn(
scope = viewModelScope,
started = SharingStarted.Eagerly,
initialValue = store.state
)
val sideEffects = store.sideEffects
fun increment() {
store.accept(CounterStore.Intent.Increment)
}
fun decrement() {
store.accept(CounterStore.Intent.Decrement)
}
fun reset() {
store.accept(CounterStore.Intent.Reset)
}
}
Высокія функцыі
Бібліятэка Конфігурацыя
SimpleMVI прапануе глыбокую сістэму канфігурацыі:
configureSimpleMVI {
// Strict error handling mode (throws exceptions)
strictMode = true
// Logger configuration
logger = object : Logger {
override fun log(message: String) {
// Your logging implementation
}
}
}
Невядомыя мадэлі
- strictMode = true - бібліятэка працуе ў строгім рэжыме і выкідае выключэнні, калі выяўленыя няправільныя
- strictMode = false (падрабязна) - бібліятэка працуе ў мёртвым рэжыме і толькі запісвае няправільнасці без спынення выканання
Поспех у справе
SimpleMVI мае спецыяльныя выключэнні:
- NotOnMainThreadException - пры спробе выклікаць метады Store не з асноўнага дроту
- StoreIsNotInitializedException — калі вы спрабуеце выкарыстоўваць Uninitialized Store
- StoreIsAlreadyDestroyedException - пры справе выкарыстання ўжо знішчанага Магазіну
Выпрабаванне элементаў
Дзякуючы чыстым распаўсюджванню адказнасці, SimpleMVI кампаненты лёгка выпрабаваць:
// Example of Store testing
@Test
fun `increment should increase counter by 1`() {
// Arrange
val store = CounterStore()
store.init()
// Act
store.accept(CounterStore.Intent.Increment)
// Assert
assertEquals(1, store.state.count)
assertTrue(store.state.isPositive)
// Cleanup
store.destroy()
}
Высновы
Сярод версій гульняў онлайн call of duty можна знайсці мноства займальных і дасціпных сюжэтаў, а апошняй навінкай, выпушчанай у канцы восені гэтага года, стала гульня Call of Duty: Ghost.
Ключавыя перавагі SimpleMVI
Напрыклад, можна вызначыць наступныя сілы бібліятэкі:
Мінімалістычны і прагматычны погляд
Напэўна, мы не з’яўляемся нейкімі паддоследнымі суб’ектамі, на якіх Бог эксперыментуе, спасылаючы нейкія цяжкасці і выпрабаванні.
Поўная падтрымка мультыплатформы Kotlin
Будаваны на Kotlin з нуля, SimpleMVI апынуўся для развіцця на некалькіх платформах. Бібліятэка ізалявае платформы-спецыфічны код праз механізм чакаць / рэальны, забяспечваючы сумяшчальнасць з Android, iOS, macOS і wasm js.
3.Предсказальнае дзяржаўнае кіраванне
Варта адзначыць, што ў Call of Duty 4 місіі даюць вельмі шмат бонусаў і ачкоў развіцця, да таго ж, яны досыць цікавыя і незвычайныя - выконваць іх лёгка і нясумна.
Галоўная / Заявы і абмоўкі пра абмежаванне адказнасці
Варта адзначыць, што ў Call of Duty 4 місіі даюць вельмі шмат бонусаў і ачкоў развіцця, да таго ж, яны досыць цікавыя і незвычайныя - выконваць іх лёгка і нясумна.
Зручны DSL для дэкларацыйнага логічнага апісання
Афары́зм (па-грэцку: αφορισμός — выказваньне) — выслоўе, у якім у трапнай, ляканічнай і звычайна вобразнай форме выказаная арыгінальная думка.
Флексіфікацыя і экспансійнасць
Не палічыце сарказмам, але тое, што адбываецца цяпер, вельмі нагадвае прымітыўную спробу даказаць: у «рускім свеце» усё самае лепшае.
Класічныя выпадкі выкарыстання
SimpleMVI вельмі падыходзіць для наступных сцэнарый:
Колькасць мультыплатформных праектаў
Калі вы распрацоўваеце прыкладанне, якое трэба працаваць на некалькіх платформах (Android і iOS, вэб-прыкладанняў), SimpleMVI дазваляе выкарыстоўваць адзін архітэктурны падыход і сумесны бізнес-логічны код.
Заявы і абмоўкі пра абмежаванне адказнасці
Варта адзначыць, што ў Call of Duty 4 місіі даюць вельмі шмат бонусаў і ачкоў развіцця, да таго ж, яны досыць цікавыя і незвычайныя - выконваць іх лёгка і нясумна.
Праекты з акцэнтам на тэставальнасць
Варта адзначыць, што для ажыццяўлення работ па стварэнні Нацыянальнага інвентара нематэрыяльнай культурнай спадчыны наша краіна летась атрымала грант з адпаведнага фонду UNESCO.
Міграцыя існуючых праектаў у архітэктуру MVI
SimpleMVI можа быць уведзены паступова, пачынаючы з асобных модуляў або функцый, што робіць яго прыдатным для паступовай міграцыі існуючых праектаў у архітэктуру MVI.
5 Навуковыя праекты і пратэсты
Дзякуючы сваёй простыні і мінімалізму, SimpleMVI добра падыходзіць для выкладання МVI-прынцыпаў і для хуткага прататыпавання.
Задачы для далейшага навучання
Для тых, хто хоча падымаць свае веды аб SimpleMVI і MVI архітэктуры ў цэлым, я рэкамендую наступныя рэсурсы:
- SimpleMVI GitHub repository — крыніцавы код бібліятэкі з прыкладамі выкарыстання
- SimpleMVI Documentation — афіцыйная дакументацыя з падрабязным апісаннем API і рэкамендацыямі
Заключныя думкі
SimpleMVI з'яўляецца збалансаваным рашэннем для арганізацыі прыкладання бізнес-логікі з выкарыстаннем сучасных падыходаў да архітэктуры.
Але серыя онлайн цацак Assassins creed 3 і Assassins creed 4, а таксама астатнія часткі забавы таксама заслугоўваюць увагі і вывучэння.
Размова сапраўды вельмі важная — мы ж усе цудоўна разумеем, што любы, самы лепшы дэкрэт можна звесці на нішто практыкай прымянення.