Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Business logic in Vue.js
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Sobolev Nikita
August 22, 2019
Programming
320
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Business logic in Vue.js
Sobolev Nikita
August 22, 2019
More Decks by Sobolev Nikita
See All by Sobolev Nikita
Чего вы не знали о строках в Python – Василий Рябов, PythoNN
sobolevn
0
240
ИИ-Агенты в каждый дом – Алексей Порядин, PythoNN
sobolevn
0
200
Внутреннее устройство сборки мусора в CPython 3.14+ – Сергей Мирянов, PythoNN
sobolevn
0
120
Генератор байткода и байткод генератора, Михаил Ефимов, PythoNN
sobolevn
0
110
Дотянуться до кремния. HighLoad Python: SIMD, GPU – Пётр Андреев, PythoNN
sobolevn
0
110
Проектирование — это когда чувствуешь, а не какие-то там циферки, Николай Хитров, PythoNN
sobolevn
0
130
Continuous profiling, Давид Джалаев, PythoNN
sobolevn
0
150
Михаил Гурбанов – Are you NATS? @ PythoNN
sobolevn
0
290
Дмитрий Бровкин – Почему исправление опечаток сложнее, чем кажется, и как мы с этим српавляемся @ PythoNN
sobolevn
0
68
Other Decks in Programming
See All in Programming
LLM本来の能力を解き放つサンドボックス技術とAI民主化への適用
yukukotani
3
3.5k
ADKを使って簡単にAIエージェントを作ってみよう
k1mu21
0
250
[2026年度第1回ORセミナー] 計画最適化ベンチャーと競技プログラミング人材
terryu16
0
250
セキュリティの専門家じゃなくてもできる。「セキュリティ意識」をアップデートして サプライチェーン攻撃への耐性を高めよう。
tk3fftk
5
690
「エンジニアインターン、どうやって取った?」準備のリアルを語るLT会 Progate BAR
akiomatic
0
130
JJUG CCC 2026 Spring: JSpecify で実現する Kotlin フレンドリーな Java API 設計
ternbusty
1
160
スマートグラスで並列バイブコーディング
hyshu
0
110
Skillsは効率化、Agentsは"自分の拡張"——Builder時代のエージェント編成(CC Night 2026)
wemra
1
120
These Five Tricks Can Make Your Apps Greener, Cheaper, & Nicer
hollycummins
0
280
過去最大のMCPアップデート! 2026-07-28 RC版の謎に迫る
licux
6
210
PHPで使える日時の表現と、その知り方 #frontend_phpcon_do
o0h
PRO
0
230
Agentic UI
manfredsteyer
PRO
0
130
Featured
See All Featured
A Tale of Four Properties
chriscoyier
163
24k
Joys of Absence: A Defence of Solitary Play
codingconduct
1
390
Crafting Experiences
bethany
1
170
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
Test your architecture with Archunit
thirion
1
2.3k
The Language of Interfaces
destraynor
162
27k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
200
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
600
So, you think you're a good person
axbom
PRO
2
2.1k
The B2B funnel & how to create a winning content strategy
katarinadahlin
PRO
1
380
[RailsConf 2023] Rails as a piece of cake
palkan
59
6.7k
Transcript
Никита Соболев github.com/sobolevn 1
Бизнес логика и Vue.js !2
Композиция и абстракция !3
Но во Vue.js - компоненты! !4
отображение = f(состояния) !5
отображение = f(состояния) !6
export default { data () { return { username: ''
} }, template: ` <button click="loadUser">Hello {{ username }}</button> `, loadUser () { this.username = this.$axios.get('...').data }, } !7
отображение = f(состояния) !8
export default { data () { return { username: ''
} }, template: ` <button click="loadUser">Hello {{ username }}</button> `, loadUser () { this.username = this.$axios.get('...').data }, } !9
export default { data () { return { username: ''
} }, template: ` <button click="loadUser">Hello {{ username }}</button> `, loadUser () { this.username = this.$axios.get('...').data }, } !10
f = check( transform( fetch() ) ) !11
f = fetch() |> transform() |> check() !12
Кто видит проблему? !13
Изменение логики !14
export default { data () { return { username: ''
} }, template: ` <button click="loadUser">Hello {{ username }}</button> `, loadUser () { this.username = localStorage.getItem('user') }, } !15
Плохие решения • Сделать два компонента • Передавать callback в
props !16
export default { // ... props: ['callback'], loadUser () {
this.username = this.callback(...) }, } !17
Вопросики • А если у нас нет возможности передать callback?
• А если очень глубокая вложенность? !18
Плохие решения • Сделать два компонента • Передавать callback в
props !19
Плохие решения • Сделать два компонента • Передавать callback в
props • Передавать флаг для поведения !20
export default { // ... props: ['http'], loadUser () {
if (this.http) { this.username = this.$axios.get(...) } else { this.username = localStorage(...) } }, } !21
Вопросики • А если поведений много? • А если у
нас нет возможности выставить флаг? • А если очень глубокая вложенность? • А как его тестировать? !22
Тестирование !23
import { mount, createLocalVue } from '@vue/test-utils' import MockAdapter from
'axios-mock-adapter' import MyComponent from '~/components/MyComponent' const localVue = createLocalVue() describe('unit tests for MyComponent', () => { test('should have correct logic', () => { const wrapper = mount(MyComponent, { localVue }) new MockAdapter(wrapper.axios) .onGet('...') .reply(200, ['sobolevn']) wrapper.loadUser() expect(wrapper.username).toBe('sobolevn') }) }) !24
Плохие решения • Терпеть !25
Хорошие решения: композиция и абстракция !26
provide / inject !27
import { mount, createLocalVue } from '@vue/test-utils' import MyComponent from
'~/components/MyComponent' const localVue = createLocalVue() describe('unit tests for MyComponent', () => { test('should have correct logic', () => { const wrapper = mount(MyComponent, { localVue, provide: { buttonCallback: () => 'sobolevn' }, }) wrapper.loadUser() expect(wrapper.username).toBe('sobolevn') }) }) !28
Рефакторинг компонента !29
export default { data () { return { username: ''
} }, template: ` <button click="loadUser">Hello {{ username }}</button> `, inject: ['buttonCallback'], loadUser () { this.username = this.buttonCallback() }, } !30
Создание контекста * https://mmhaskell.com/monads-4 !31
export default { provide: { buttonCallback: () => this.$axios.get('...'), },
components: { MyComponent }, template: `<MyComponent />`, } !32
Плохие решения • Пихать логику в компоненты • Делать вид,
что ты не пихаешь логику в компоненты !33
Рефакторинг компонента !34
import buttonCallbackFactory from 'logic/http' export default { provide: { buttonCallback:
buttonCallbackFactory(...), }, components: { MyComponent }, template: `<MyComponent />`, } !35
И не только для компонентов !36
C Vue понятно, а Vuex? !37
Плохие решения • Пихать логику во Vuex !38
отображение = f(состояния) !39
Vuex !40
import { Inject, Injectable } from 'vue-typedi' import { Action
} from 'vuex-simple' @Injectable() export default class UsernameModule { @Inject(tokens.USERNAME_SERVICE) public service // type: UsernameServiceProtocol @Action() public async fetchUsername () { const username = await this.service.fetchUsername() // ... } } !41
// type: UsernameServiceProtocol
Вставляй любую абстракцию! !43
provide / inject vs TypedDI !44
И не только DI • Higher Order Components • Slots,
Named Slots • https://github.com/vuejs/vue-function-api • Event Bus • Vue.observable, https://github.com/vuejs/vue-rx !45
Сегодня мы многое поняли !46
github.com/wemake-services/ wemake-vue-template !47
Полезные инструменты • https://github.com/sascha245/vue-typedi • https://github.com/typestack/typedi • https://github.com/gcanti/io-ts • https://github.com/gcanti/fp-ts
!48
Полезные ссылки • https://guide.elm-lang.org/architecture/ • https://markus.oberlehner.net/blog • https://blog.ploeh.dk/2016/03/18/functional- architecture-is-ports-and-adapters/ •
https://fsharpforfunandprofit.com/rop/ • https://www.destroyallsoftware.com/screencasts/ catalog/functional-core-imperative-shell • https://sobolevn.me/ !49
tlg.name/ opensource_findings !50
Вопросы? github.com/sobolevn sobolevn.me 51