Ответ скрыл под спойлер, а так же прилагаю ссылку в ноушене для детального изучения
🔥5👍4🕊3
Выполнение асинхронных задач в SwiftUI
Начиная с iOS 14 вместо Task {…} в onAppear начинаем юзать встроенный модификатор .task – он сам создаёт и отменяет задачу вместе с жизненным циклом View:
Но зачем так делать?
- Не надо городить Task вручную и переживать об отмене.
- Внутри .task {} у тебя сразу async-контекст – можно вызывать await напрямик.
- Логика асинхронки отделена от onAppear и проще читается.
Но это ещё не всё. Если нужна реакция на изменения, например ты стал что-то вводить, то ты можешь вызывать конструктор с id:
Теперь при изменении query предыдущая задача отменяется автоматически. Но и это ещё не все!
Ты можешь управлять приоритетом. По умолчанию приоритет – .userInitiated, но можно указать свой и для этого можно взять соответствующий конструктор:
Используй модификатор .task, чтобы SwiftUI сам заботился о запуске и отмене твоих async-задач!
Начиная с iOS 14 вместо Task {…} в onAppear начинаем юзать встроенный модификатор .task – он сам создаёт и отменяет задачу вместе с жизненным циклом View:
Text("Привет, мир!")
.task { // ✅ запускается при появлении и отменяется при уходе
await loadData()
}
Но зачем так делать?
- Не надо городить Task вручную и переживать об отмене.
- Внутри .task {} у тебя сразу async-контекст – можно вызывать await напрямик.
- Логика асинхронки отделена от onAppear и проще читается.
Но это ещё не всё. Если нужна реакция на изменения, например ты стал что-то вводить, то ты можешь вызывать конструктор с id:
.searchable(text: $query)
.task(id: query) { // каждый раз новый `query` – новая задача
results = await fetch(query)
}
Теперь при изменении query предыдущая задача отменяется автоматически. Но и это ещё не все!
Ты можешь управлять приоритетом. По умолчанию приоритет – .userInitiated, но можно указать свой и для этого можно взять соответствующий конструктор:
.task(priority: .background) {
await cleanupCache()
}
Используй модификатор .task, чтобы SwiftUI сам заботился о запуске и отмене твоих async-задач!
🔥14👍4😎3❤1
func saveData() {
Task {
updateData()
print("Дата сохранена!")
}
func updateData() {
Task.detached {
self.isSaved = true
}
}
}
Есть переменная isSaved типа Boolean. Будет ли фиолетовая ошибка — если запустить данный код? Мыслим в парадигме работы на SwiftUI и только / Без UIKit
P.S. сама сущность где отработает saveData() без аннотации @MainActor
🕊 - ДА / НЕТ
-----
Через 10 минут ответ в скрытом тексте, удачи 🙂
UPD:
- Если использовать макрос observable, там это не нужно и поэтому НЕТ, в контексте и ДА и НЕТ тоже верно, т.е смайл 🕊.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14👎2🕊2
Проверка на знание типов - но НААААМНОГО интереснее
Есть такая приватная функция _isPOD:
По-сути мы должны вспомнить, что есть что:
- Что есть примитивы
- Что есть ref type
- Что есть value type + ref type
И тветить будет ли выводить принт true или же false. Ну и самособой почему?🤔
Вот вам сам код:
И попробуй посмотреть на этот код и ответить:"Где true, а где false?". Ну а когда закончишь, то проверить можешь здесь.
Есть такая приватная функция _isPOD:
Приватная underscore функция проверяет, можно ли битово копировать метаданные типа без дополнительных операций retain / release или других скрытых семантик копирования /деструкции.
Если все поля типа сами являются POD: примитивные числовые типы, тривиальные структуры без custom инициализаторов или ссылочных полей, функция возвращает true; при наличии хотя бы одного неподы POD-поля — false.
По-сути мы должны вспомнить, что есть что:
- Что есть примитивы
- Что есть ref type
- Что есть value type + ref type
И тветить будет ли выводить принт true или же false. Ну и самособой почему?
Вот вам сам код:
struct A {
let one: StaticString
let two: Int
}
struct B {
let one: String
let two: Int
}
struct C {
let one: [String]
}
struct D {
let one: () -> Void
}
struct E {
let one: D
}
class F {
let one: Int = 2
}
struct G {
let one: Int
}
struct H {
let one: (Int, Float)
}
print(_isPOD(A.self))
print(_isPOD(B.self))
print(_isPOD(C.self))
print(_isPOD(D.self))
print(_isPOD(E.self))
print(_isPOD(F.self))
print(_isPOD(G.self))
print(_isPOD(H.self))
И попробуй посмотреть на этот код и ответить:"Где true, а где false?". Ну а когда закончишь, то проверить можешь здесь.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6❤4👍3
Подскажите пожалуйста, мы такое асуждаем или не асуждаем?
👍- асуждаем
👎- не асуждаем
https://ilovehackit.ru
👍- асуждаем
👎- не асуждаем
https://ilovehackit.ru
👍35👎19
Различие между наследование флага и автоматической отмены
Когда погружаешься в изучение structured concurrency, то можно упустить или запамятовать некоторые детали, а они бывают важными.
Так например есть разница между structured и unstructured tasks. И здесь даже можно спутаться, что есть structured, что есть unstructured... Но Apple отетила на этот вопрос твёрдо и чётко.
И здесь мы можешь заметить, что Task нарушает. А чтобы проверить, достаточно запустить и проверить:
И мы увидим, что это не одно и тоже как если бы мы поступили с представителем structured tasks - withThrowingTaskGroup:
Когда погружаешься в изучение structured concurrency, то можно упустить или запамятовать некоторые детали, а они бывают важными.
Так например есть разница между structured и unstructured tasks. И здесь даже можно спутаться, что есть structured, что есть unstructured... Но Apple отетила на этот вопрос твёрдо и чётко.
Структурированная конкурентность требует:
1. Scoped lifetime: дочерние задачи не могут пережить родительскую задачу.
2. Автоматическое ожидание: родитель должен дождаться всех дочерних задач перед завершением.
3. Fail-fast behavior: ошибки в дочерних задачах распространяются на родительскую.
4. Строгая иерархия parent-child: четкие отношения для распространения отмены и приоритета.
И здесь мы можешь заметить, что Task нарушает. А чтобы проверить, достаточно запустить и проверить:
func demonstrateUnstructuredTaskCancellation() async {
print("🔵 Демонстрация Task {} - unstructured")
let parentTask = Task {
print("👨 Parent task начала работу")
let childTask = Task {
print("👶 Child task начала работу")
// Проверяем отмену каждую секунду
for i in 1...5 {
if Task.isCancelled {
print("👶 Child обнаружила отмену на итерации \(i)")
return "Child завершилась по отмене"
}
print("👶 Child работает... итерация \(i)")
try? await Task.sleep(nanoseconds: 1_000_000_000)
}
print("👶 Child завершила всю работу")
return "Child успешно завершилась"
}
// Ждем немного и отменяем parent
try? await Task.sleep(nanoseconds: 2_500_000_000)
print("👨 Parent отменяется!")
// Получаем результат child
let result = await childTask.value
print("👨 Parent получил результат: \(result)")
return "Parent завершен"
}
// Отменяем parent task через 2.5 секунды
parentTask.cancel()
let finalResult = await parentTask.value
print("🔵 Финальный результат: \(finalResult)")
print("🔵 Обратите внимание: child task продолжила работу после отмены parent!\n")
}
// Запуск примера
await demonstrateUnstructuredTaskCancellation()
И мы увидим, что это не одно и тоже как если бы мы поступили с представителем structured tasks - withThrowingTaskGroup:
👍3🔥2
func demonstrateStructuredTaskCancellation() async {
print("🟢 Демонстрация TaskGroup - structured")
do {
try await withThrowingTaskGroup(of: String.self) { group in
print("👨 TaskGroup начала работу")
// Запускаем три дочерние задачи
for i in 1...3 {
group.addTask {
print("👶 задача \(i) начала работу")
for j in 1...5 {
try Task.checkCancellation() // бросит CancellationError, если отменена
print("👶 задача \(i) итерация \(j)")
try await Task.sleep(nanoseconds: 1_000_000_000)
}
print("👶 задача \(i) завершилась")
return "задача \(i) успех"
}
}
// Ждём 2.5 секунды в этой же области и отменяем группу
try await Task.sleep(nanoseconds: 2_500_000_000)
print("👨 TaskGroup отменяет все задачи!")
group.cancelAll()
// Сбор завершённых результатов
var results: [String] = []
for try await result in group {
results.append(result)
print("👨 Получен результат: \(result)")
}
print("👨 TaskGroup завершена. Всего результатов: \(results.count)")
}
} catch {
print("🟢 TaskGroup завершилась с ошибкой: \(error)")
}
print("\n🟢 Все дочерние задачи в группе гарантированно либо отработали, либо были отменены.")
}
// Запуск примера
await demonstrateStructuredTaskCancellation()
Вот такой, небольшой, но интересный нюанс между наследованием флага отмены и автоматической отменой.
👍3🔥3
Swift Server Side Meetup #5
Да-да, движется по-немногоу. Прям как и сам язык swift в серверную разработку. Конечно свифту ещё далеко, но для тех кто на приколе серверной части для свита - рекомендую.
https://www.youtube.com/watch?v=0JrLkHgZa-k
Да-да, движется по-немногоу. Прям как и сам язык swift в серверную разработку. Конечно свифту ещё далеко, но для тех кто на приколе серверной части для свита - рекомендую.
https://www.youtube.com/watch?v=0JrLkHgZa-k
YouTube
Swift Server Side Meetup #5
**📅 Monday, June 23rd, 2025**
**🕖 7pm CEST (10am PDT / 1pm EDT)**
**🌐 Online – no registration needed**
We’re excited to invite you to the next Swift Server Side Meetup, where Swift takes a bold step into the physical world—from embedded microcontrollers…
**🕖 7pm CEST (10am PDT / 1pm EDT)**
**🌐 Online – no registration needed**
We’re excited to invite you to the next Swift Server Side Meetup, where Swift takes a bold step into the physical world—from embedded microcontrollers…
👍3🔥3❤1
🔥6❤3
#заметка #array #устройство_работы
Пустые массивы в Swift оптимизированы через глобальный singleton
1) Экономию памяти - избегается выделение heap объектов для каждого пустого массива.
2) Производительность - нет вызовов malloc / free для пустых массивов.
При первом добавлении элемента в пустой массив:
Создается новый buffer с реальной capacity, а ссылка на
Что делать с этой информацией? - Да фиг его знает. Можно блатануть на собеседовании, или на pull-request'e (merge request), когда кто-то заводит пустой массив, а ему накинули комментариев:"nit(гнида), лишние ресурсы"
cc: https://github.com/swiftlang/swift/blob/main/stdlib/public/core/ContiguousArray.swift
сс: https://github.com/swiftlang/swift/blob/main/stdlib/public/core/ContiguousArrayBuffer.swift
cc: https://stackoverflow.com/questions/45116205/swifts-array-type-is-bridged-to-foundations-nsarray-class-how
Пустые массивы в Swift оптимизированы через глобальный singleton
_emptyArrayStorage, который статически инициализируется в runtime и используется всеми пустыми массивами независимо от типа элементов. Это решение экономит память и улучшает производительность.1) Экономию памяти - избегается выделение heap объектов для каждого пустого массива.
2) Производительность - нет вызовов malloc / free для пустых массивов.
При первом добавлении элемента в пустой массив:
@inlinable
@_semantics("array.mutate_unknown")
internal mutating func _reserveCapacityAssumingUniqueBuffer(oldCount: Int) {
// Due to make_mutable hoisting the situation can arise where we hoist
// _makeMutableAndUnique out of loop and use it to replace
// _makeUniqueAndReserveCapacityIfNotUnique that precedes this call. If the
// array was empty _makeMutableAndUnique does not replace the empty array
// buffer by a unique buffer (it just replaces it by the empty array
// singleton).
// This specific case is okay because we will make the buffer unique in this
// function because we request a capacity > 0 and therefore _copyToNewBuffer
// will be called creating a new buffer.
let capacity = _buffer.mutableCapacity
_internalInvariant(capacity == 0 || _buffer.isMutableAndUniquelyReferenced())
if _slowPath(oldCount &+ 1 > capacity) {
_createNewBuffer(bufferIsUnique: capacity > 0,
minimumCapacity: oldCount &+ 1,
growForAppend: true)
}
}
Создается новый buffer с реальной capacity, а ссылка на
_emptyArrayStorage освобождается, шутки про Джанго отставить!Что делать с этой информацией? - Да фиг его знает. Можно блатануть на собеседовании, или на pull-request'e (merge request), когда кто-то заводит пустой массив, а ему накинули комментариев:"nit(гнида), лишние ресурсы"
cc: https://github.com/swiftlang/swift/blob/main/stdlib/public/core/ContiguousArray.swift
сс: https://github.com/swiftlang/swift/blob/main/stdlib/public/core/ContiguousArrayBuffer.swift
cc: https://stackoverflow.com/questions/45116205/swifts-array-type-is-bridged-to-foundations-nsarray-class-how
🔥6🤔6👍2🥴1
#заметка #cow #устройство_работы
А ты знал, что Swift хранит счетчик сильных ссылок как "extra count" - дополнительное значение?🤔
Когда у объекта одна strong ссылка, в памяти хранится 0.
Когда две ссылки — хранится 1.
- Физическое значение = то, что реально хранится в битах.
- Логическое значение = реальное количество ссылок = физическое + 1
Именно поэтому
Это как номерки в гардеробе, которые начинаются с 0, а не с 1. Apple сэкономила на единичке, потому что одна ссылка — самый частый случай. А когда у нас миллиарды объектов, даже один бит на счету!
Представь диалог:
- Сколько у тебя ссылок?
- Ноль!
- То есть объект мёртв?
- Нет, это значит одна! Просто мы экономные
Մտածեք. Բաժանորդագրվել.
cc: https://github.com/swiftlang/swift/blob/eb29949fe7d2c90644410ef9cef76abe30658aad/stdlib/public/SwiftShims/swift/shims/RefCount.h#L609C3-L626C4
А ты знал, что Swift хранит счетчик сильных ссылок как "extra count" - дополнительное значение?
Когда у объекта одна strong ссылка, в памяти хранится 0.
Когда две ссылки — хранится 1.
- Физическое значение = то, что реально хранится в битах.
- Логическое значение = реальное количество ссылок = физическое + 1
// Практический пример с Copy-on-Write:
var array1 = [1, 2, 3]
// StrongExtraRefCount = 0 (в памяти)
// Реальных ссылок = 1 ✅ Можно изменять!
var array2 = array1
// StrongExtraRefCount = 1 (в памяти)
// Реальных ссылок = 2 ❌ Нужно копировать!
array2.append(4)
// Swift проверяет: getStrongExtraRefCount() == 0?
// Нет! Значит создаём копию массива
Именно поэтому
isKnownUniquelyReferenced проверяет getStrongExtraRefCount() == 0 - это означает, что есть только одна ссылка на объект, и его можно безопасно изменять без копирования.
bool isUniquelyReferenced() {
static_assert(Offsets::UnownedRefCountBitCount +
Offsets::IsDeinitingBitCount +
Offsets::StrongExtraRefCountBitCount +
Offsets::PureSwiftDeallocBitCount +
Offsets::UseSlowRCBitCount == sizeof(bits)*8,
"inspect isUniquelyReferenced after adding fields");
// Unowned: don't care (FIXME: should care and redo initForNotFreeing)
// IsDeiniting: false
// StrongExtra: 0
// UseSlowRC: false
// Compiler is clever enough to optimize this.
return
!getUseSlowRC() && !getIsDeiniting() && getStrongExtraRefCount() == 0;
}
Это как номерки в гардеробе, которые начинаются с 0, а не с 1. Apple сэкономила на единичке, потому что одна ссылка — самый частый случай. А когда у нас миллиарды объектов, даже один бит на счету!
Представь диалог:
- Сколько у тебя ссылок?
- Ноль!
- То есть объект мёртв?
- Нет, это значит одна! Просто мы экономные
Մտածեք. Բաժանորդագրվել.
cc: https://github.com/swiftlang/swift/blob/eb29949fe7d2c90644410ef9cef76abe30658aad/stdlib/public/SwiftShims/swift/shims/RefCount.h#L609C3-L626C4
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
swift/stdlib/public/SwiftShims/swift/shims/RefCount.h at eb29949fe7d2c90644410ef9cef76abe30658aad · swiftlang/swift
The Swift Programming Language. Contribute to swiftlang/swift development by creating an account on GitHub.
🔥5❤2👍1🌚1
#wwdc25
Improve memory usage and performance with Swift
Сессия с WWDC25, где расскажут про InlineArray и его разницу между Array из Swift, причным нам. Спойлер - копируется сразу, CoW не поддерживает. Ну и как работа с InlineArray сделает работу ещё-более оптимизированной на ресурсы (график увидишь на сессии).
Так же понравилось, в самом начале, что при помощи Instruments: Time Profiler и Allocations, можно продебажить на bottle neck - "узкое горлыжко" в приложении. Посмотреть колличество аллокаций, деаллокаций, фильтранутьсветлого нужное и прыгнуть в проблемное место.
Ну и под конец будет про новую обёртку - Span. Всё это уже можно посмотреть / потрогать в Xcode 26. Жаль в wwdc notes ещё нет краткого пересказа, но возможно, он скоро будет? - Если-что вот ссылка на него 🙂
https://developer.apple.com/videos/play/wwdc2025/312
Improve memory usage and performance with Swift
Сессия с WWDC25, где расскажут про InlineArray и его разницу между Array из Swift, причным нам. Спойлер - копируется сразу, CoW не поддерживает. Ну и как работа с InlineArray сделает работу ещё-более оптимизированной на ресурсы (график увидишь на сессии).
Так же понравилось, в самом начале, что при помощи Instruments: Time Profiler и Allocations, можно продебажить на bottle neck - "узкое горлыжко" в приложении. Посмотреть колличество аллокаций, деаллокаций, фильтрануть
Ну и под конец будет про новую обёртку - Span. Всё это уже можно посмотреть / потрогать в Xcode 26. Жаль в wwdc notes ещё нет краткого пересказа, но возможно, он скоро будет? - Если-что вот ссылка на него 🙂
https://developer.apple.com/videos/play/wwdc2025/312
Apple Developer Documentation
Span | Apple Developer Documentation
represents a contiguous region of memory which contains initialized instances of .
👍5❤1🔥1
#middle #задачка
Что из перечисленного ниже нельзя переопределить в подклассе? Опрос будет ниже🤖
Что из перечисленного ниже нельзя переопределить в подклассе? Опрос будет ниже
class Vehicle {
static let wheels = 4
class var description: String {
return "Vehicle with \(wheels) wheels"
}
}
class Motorcycle: Vehicle {
override static let wheels = 2
override class var description: String {
return "Motorcycle with 2 wheels"
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
#заметка #soft_skills
История одной задачи + софт скиллы в деле с QA и Backend
Доброго дня. Решил начать писать небольшие заметки про софт скиллы. Кто знает, мб в отдельное видео, со структурой и гайдом выйдет. Но пока этого нет - буду чуть по чуть сюда писать интересные вещи.
Давечне мне надо было починить баг - отсутствие переводов для некоторых языков. Этот баг выглядит просто:"Наверное затерялась локализация для необходимы языков, сейчас пойду поправлю. Делов на 5 минут."
Так как проект немаленький, то найти нужные строки и нужный участок кода - дело не на 5 минут, а минут на 15. Хотя хотелось - бы на 5, но что поделать... Нашел нужное место, оказалось, что дело не в строках или ключах, а в том, что бекенд присылает текст всегда на англйиском.
Иду смотреть в задачу, и нигде не вижу об этом ни слова. И тут я хотел-бы добавить, что не во всех компаниях или проектах тестировщики должны собирать логи. Или собирать логи прям везде и до 3-его колена. Нет, всё как всегда просто - как договорились, так и будете работать.
Так вот, оказывается тестер не написал этот факт, что текст приходит с бекенда, и что iOS тут особо ничего и не сделает, а задча должна БЫЛА БЫ содержать лейбл [backend], а не [iOS], но что поделать...
Иду до тестера и кумекаю, что так и так, что задача так-то не про iOS, а про backend, но тестеру не нужно волноваться, я сейчас схожу и уточню.
Иду в нужное место, тегаю PM, Backend и пишу, что текст, который багает, он приходит бекенда, и что лучше править на бекенде в одном месте, чем на iOS и Android отдельно - в двух местах. И аргументирую это тем, что если править на 2-ух платформах сразу, то это придётся:
А зачем править в двух местах одинаковой логикой, плюс закидывать текста, которые сейчас присылает, хоть и частично, бекенд - если на бекенде можно доработать, в одном месте.
Cверху накинул, что можно взять текущую ручку, добавить к ней параметр языка, чтобы backend'у было проще, при реализации фикса, принимать параметр языка и с ним уже идти за переводом и отдавать нужный текст, а не стучаться в микросервис локализации, смотреть текущую локаль и только после этого отдавать нужный текст.
Какой вывод можно сделать из этой истории?
Не стоит идти к тестировщику и как-то язвить или сетовать на то, что он оказался где-то неправ. Потому-что напомню:
- Как договорились в команде так и будет.
- Опыт коллеги, кума, зятя, соседа не всегда релевантный к тебе, т.к ты не всегда знаешь всех под-капотных вещей.
Если - бы я отправил тестера вместо себя изучать, ибо проблема backend'a, то мог - бы получиться сломанный телефон из 3-ёх человек + к этому долго бы обсуждали. А лично я не люблю тягомотину эту, когда понимаешь, что с буксом + хрустом можно за 5 минут обговорить и сделать, чем 30 минут выяснять кто прав, а кто виноват и придти к такому-же результату.
Возможность для выноса на ретроспективу, чтобы тестировщики проверяли чуть глубже, если они этого не делают. А если должен делать, но конкретно тут [по какой-то причине забыл сделать], то в мягкой форме донести:"Что мне бы помогло, если-бы в результате заведения бага были логи".
Все мы люди, разные бывают обстоятельства и зачем токсичить или язвить, если можно этого не делать? - Если - вдруг ты считаешь, что токсичишь, то всегда можно:
- После написания текста не отправлять его, взять пауза на 5 минут. Спустя паузу перечитать.
- Закинуть ИИ на оценку токсичности, и в случае её обнаружения попросить поправить. А что нет то, мы ж не пишем рассказ, а доносим мысль.
Ну и последнее, чтобы backend'у было легче, я сразу же заострил внимание, что можно сделать легче и без проблем - прокинуть дополнительный параметр и по нему получать перевод. Потому-что для backend'a пойти в другой микросервис, узнать там локаль, с этими знаниями придти обратно - это лишние сложности.
А мы бы их создали, если бы могли упереться, не согласиться, дескать вот пусть backend разруливает сам ибо мы просто получаем и показываем... Разные ветви пути могли-бы быть...
История одной задачи + софт скиллы в деле с QA и Backend
Доброго дня. Решил начать писать небольшие заметки про софт скиллы. Кто знает, мб в отдельное видео, со структурой и гайдом выйдет. Но пока этого нет - буду чуть по чуть сюда писать интересные вещи.
Давечне мне надо было починить баг - отсутствие переводов для некоторых языков. Этот баг выглядит просто:"Наверное затерялась локализация для необходимы языков, сейчас пойду поправлю. Делов на 5 минут."
Так как проект немаленький, то найти нужные строки и нужный участок кода - дело не на 5 минут, а минут на 15. Хотя хотелось - бы на 5, но что поделать... Нашел нужное место, оказалось, что дело не в строках или ключах, а в том, что бекенд присылает текст всегда на англйиском.
Иду смотреть в задачу, и нигде не вижу об этом ни слова. И тут я хотел-бы добавить, что не во всех компаниях или проектах тестировщики должны собирать логи. Или собирать логи прям везде и до 3-его колена. Нет, всё как всегда просто - как договорились, так и будете работать.
Так вот, оказывается тестер не написал этот факт, что текст приходит с бекенда, и что iOS тут особо ничего и не сделает, а задча должна БЫЛА БЫ содержать лейбл [backend], а не [iOS], но что поделать...
Иду до тестера и кумекаю, что так и так, что задача так-то не про iOS, а про backend, но тестеру не нужно волноваться, я сейчас схожу и уточню.
Иду в нужное место, тегаю PM, Backend и пишу, что текст, который багает, он приходит бекенда, и что лучше править на бекенде в одном месте, чем на iOS и Android отдельно - в двух местах. И аргументирую это тем, что если править на 2-ух платформах сразу, то это придётся:
- Делать небольшую логику в 2-ух местах
- Заводить локализацию
- Маппить нужное место с нужной локализацией
А зачем править в двух местах одинаковой логикой, плюс закидывать текста, которые сейчас присылает, хоть и частично, бекенд - если на бекенде можно доработать, в одном месте.
Cверху накинул, что можно взять текущую ручку, добавить к ней параметр языка, чтобы backend'у было проще, при реализации фикса, принимать параметр языка и с ним уже идти за переводом и отдавать нужный текст, а не стучаться в микросервис локализации, смотреть текущую локаль и только после этого отдавать нужный текст.
Какой вывод можно сделать из этой истории?
Не стоит идти к тестировщику и как-то язвить или сетовать на то, что он оказался где-то неправ. Потому-что напомню:
- Как договорились в команде так и будет.
- Опыт коллеги, кума, зятя, соседа не всегда релевантный к тебе, т.к ты не всегда знаешь всех под-капотных вещей.
Если - бы я отправил тестера вместо себя изучать, ибо проблема backend'a, то мог - бы получиться сломанный телефон из 3-ёх человек + к этому долго бы обсуждали. А лично я не люблю тягомотину эту, когда понимаешь, что с буксом + хрустом можно за 5 минут обговорить и сделать, чем 30 минут выяснять кто прав, а кто виноват и придти к такому-же результату.
Возможность для выноса на ретроспективу, чтобы тестировщики проверяли чуть глубже, если они этого не делают. А если должен делать, но конкретно тут [по какой-то причине забыл сделать], то в мягкой форме донести:"Что мне бы помогло, если-бы в результате заведения бага были логи".
Все мы люди, разные бывают обстоятельства и зачем токсичить или язвить, если можно этого не делать? - Если - вдруг ты считаешь, что токсичишь, то всегда можно:
- После написания текста не отправлять его, взять пауза на 5 минут. Спустя паузу перечитать.
- Закинуть ИИ на оценку токсичности, и в случае её обнаружения попросить поправить. А что нет то, мы ж не пишем рассказ, а доносим мысль.
Ну и последнее, чтобы backend'у было легче, я сразу же заострил внимание, что можно сделать легче и без проблем - прокинуть дополнительный параметр и по нему получать перевод. Потому-что для backend'a пойти в другой микросервис, узнать там локаль, с этими знаниями придти обратно - это лишние сложности.
А мы бы их создали, если бы могли упереться, не согласиться, дескать вот пусть backend разруливает сам ибо мы просто получаем и показываем... Разные ветви пути могли-бы быть...
🔥4👍2❤1