Мобильный трудоголик
1.37K subscribers
61 photos
9 videos
266 links
👨‍💻 Пишу простым языком об iOS разработке на Swift и мобильной разработке в целом.
🔹 Вошел в IT задолго до того как это стало мейнстримом.
---
‍Обо мне: https://t.me/hardworkerIT/3
Чат: @hardworkerChatIT
Канал про разработку и жизнь в ИТ: @itDenisov
Download Telegram
👨‍💻 Жесткая правда об IT: почему айтишники выгорают быстрее всех.

Если вы до сих пор верите, что IT это только кожаные кресла, креатив и зарплаты как в Кремниевой долине, приготовьтесь к жесткому разочарованию. Реальность куда прозаичнее.

За последние годы я наблюдал всю эволюцию IT-карьеры — от восторженных новичков, мечтающих изменить мир, до выгоревших senior'ов, считающих минуты до дедлайна. И сейчас готов рассказать, почему IT это не мечта, а работа со своими правилами, подводными камнями и… возможностями.


1️⃣ «Программист только пишет код».

На самом деле, код это лишь 30% работы. Остальное:

🔹 Созвоны с заказчиками, которые сами не знают, чего хотят.
🔹 Разбор чужих багов и легаси-кода, который страшнее кошмара.
🔹 Чтение документации и бесконечные митинги.
🔹 Общение с ИИ (да, теперь и это часть работы!).


2️⃣ «В IT платят бешеные деньги».

Да, зарплаты выше среднего, но:

🔹 Junior'ы часто получают меньше офис-менеджера.
🔹 Зарплата senior'а в регионах ≈ 230к — это достойно, но не роскошно.
🔹 В аутсорсе клиент платит $50/час, а ты получаешь максимум $25, остальное идет на менеджмент, аренду и прибыль компании.


3️⃣ «Работа в крупной компании — предел мечтаний».

Мечтать о карьере в IT-гигантах — естественно. Но реальность крупных корпораций часто отличается от ожиданий:

🔹 Технологическая лотерея: вас могут перебросить с привычного стека на абсолютно чужую технологию без согласования. Сегодня вы пишете на Swift, завтра поддерживаете legacy-проект на Objective-C.
🔹 Винтик в системе: ваша индивидуальность и амбиции часто не имеют значения. Вы часть огромного механизма, где важнее процессы, чем люди.
🔹 Бессмысленный труд: можно годами работать над проектом, который внезапно закроют «по стратегическим причинам». Ваш код может никогда не увидеть пользователей.


💼 Карьера: рост или иллюзия?

Грейд junior/middle/senior часто зависят не от навыков, а от:

🔹 Политики компании (в продукте растут медленнее, в аутсорсе быстрее).
🔹 Умения продавать себя на собеседованиях.
🔹 Везучести.

Можно быть junior’ом с 3 годами опыта или senior’ом с 2. Все решает компания, а не объективные критерии.


Фриланс: свобода или ловушка?

Мечтать о работе «на себя» естественно, но фриланс в IT это:

🔹 Быть одновременно разработчиком, менеджером и продажником.
🔹 Тратить до 70% времени на поиск клиентов и переговоры.
🔹 Конфликт ролей: то, что вы продали, потом придется делать самим.

Фриланс выгоден только тем, кто умеет продавать.


⚠️ Так что же делать? Как выжить в IT?

🔹 Принять реальность: IT не рай, а работа с плюсами и минусами. Как и любая другая.
🔹 Прокачивать софт-скиллы: умение договариваться, объяснять и продавать идеи важнее знания фреймворков.
🔹 Следить за здоровьем: спорт не опция, а необходимость. Сидячий образ жизни убивает быстрее дедлайнов.
🔹 Не гнаться за грейдом: senior в одной компании ≠ senior в другой. Цените знания, а не звания.
🔹 Рассматривать смежные области: devOps, data engineering, AI.. Там, где больше денег и меньше конкуренции.


💡 Вывод:

IT это не приговор, а осознанный выбор. Да, здесь хватает рутины и выгорания, но именно эта сфера даёт возможность работать откуда угодно, постоянно расти и получать достойный доход.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👀24👍1142🔥1🤯1🙏1
🔢 Swift 6.2 вышел: интересные фичи для практической разработки.

Swift 6.2 — самое значимое обновление языка за последние годы. Рассказываю о самых интересных изменениях и как это повлияет на вашу ежедневную разработку.


🚀 Concurrency: теперь проще и безопаснее.

Главное изменение: больше не нужно постоянно ставить @MainActor. Теперь можно включить режим, где весь код по умолчанию работает на главном потоке:


// Раньше:
@MainActor
func updateUI() {
}

// Теперь:
func updateUI() {
// Автоматически на главном потоке
}


Для тяжелых задач появился @concurrent:


@concurrent
func processImage(_ image: UIImage) async -> UIImage {
// Выполняется в фоне, не блокируя интерфейс
return applyFilters(image)
}



🔒 Безопасность памяти на максимум.

Новые типы для системного программирования:

🔹 InlineArray — массив фиксированного размера в стеке:


struct GameLevel {
var enemies: [100 of Enemy] // Фиксированный размер
}


🔹 Span — безопасный срез данных:


let data = [1, 2, 3, 4, 5]
let slice = Span(data, start: 1, count: 3) // [2, 3, 4]


Строгая проверка памяти: компилятор теперь жестче следит за небезопасными операциями.


⚡️ Улучшения для разработки.

🔹 VS Code теперь официально поддерживается:

🔸 Фоновая индексация.
🔸 Встроенный отладчик LLDB.
🔸 Live-превью документации.

🔹 Быстрая сборка макросов: время clean build уменьшилось в разы.

🔹 Умные предупреждения: можно тонко настраивать:


.target(
name: "MyApp",
swiftSettings: [
.treatAllWarnings(as: .error),
.treatWarning("Deprecated", as: .warning)
]
)



Testing 2.0

🔹 Тестирование крашей:


@Test func appCrashesOnInvalidInput() {
#expect(exitCode: .failure, when: app.processInvalidInput())
}


🔹 Вложения в тестах: добавляйте логи, скриншоты, данные:


@Test func userLogin() {
attach(loginRequestData, name: "Request")
attach(screenshot(), name: "UI State")
}



🌐 Поддержка WebAssembly.

Теперь можно компилировать Swift в Wasm и запускать в браузере:


swift build --target wasm32-unknown-wasip1



🔗 Остальные изменения


💡 Вывод:

Swift 6.2 — это фундаментальный шаг в развитии языка, делающий его безопаснее, быстрее и удобнее для разработчиков.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
12714👍32🔥1🙏1
🌐 Wasm и Swift: мост между нативными и веб-приложениями.

Если вы еще не слышали о WebAssembly (Wasm) — это технология, позволяющая запускать код на любых платформах: в браузере, на сервере, в мобильных приложениях. Think of it as universal bytecode для веба и не только.


🤔 Зачем Wasm Swift-разработчику?

🔸 Кроссплатформенность: один код для iOS, Android, Web и серверов.
🔸 Производительность: скорость выполнения, близкая к нативному коду.
🔸 Безопасность: песочница и изоляция по умолчанию.
🔸 Интероперабельность: работа с JavaScript, C++, Rust.

Как и писал ранее про добавление поддержки Wasm в Swift 6.2 — за лето, с момента анонса, экосистема сделала огромный рывок.


⚙️ Embedded Concurrency:

Работает в двух средах:


# CLI-приложения
swift run --target wasm32-unknown-wasip1

# Браузер через JavaScriptKit
import JavaScriptEventLoop // Для асинхронности в браузере



🗃 CI и пакеты:

Автосборка для основных пакетов Swift:

🔸 swift-algorithms
🔸 swift-collections
🔸 swift-nio
🔸 swift-foundation (теперь входит в SDK)


Вот что уже работает сегодня:

🔹 Сборка комплексных проектов:


swift build --target wasm32-unknown-wasip1


🔹 Использование Foundation (кроме Embedded Swift):


import Foundation
// Работает с URLSession, JSONDecoder и т.д.


🔹 Интеграция с JavaScript:


// Через JavaScriptKit
let result = JSObject.global.document.createElement("div")



Что еще в работе:

🔸 Полная поддержка Embedded Swift Concurrency.
🔸 WASI Preview 2 (wasip2).
🔸 Стабилизация Foundation для Embedded.


💡 Вывод:

Wasm в Swift переходит из стадии эксперимента в production-ready. Уже сейчас можно собирать реальные проекты — от CLI-утилит до браузерных приложений. Главное преимущество — единая кодобаза для разных платформ.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍39🔥167🤯2🙏111
👨‍💻 iOS 26: почему нативная разработка становится must-have.

С выходом iOS 26 разрыв между нативными и кроссплатформенными решениями стал очевиден как никогда. Новый дизайн Liquid Glass, Apple Intelligence и интерактивные виджеты работают на полную мощность только в нативных приложениях. Flutter и другие кросс-платформенные фреймворки сталкиваются с растущими ограничениями: от задержек в поддержке новых функций до сложностей с интеграцией системных возможностей.


⚠️ Ключевые преимущества натива в iOS 26:

1️⃣ Полная интеграция с системой:

// Liquid Glass работает из коробки
struct ContentView: View {
var body: some View {
Text("Hello iOS 26!")
.glassBackgroundEffect() // Нативный эффект
}
}



2️⃣ Мгновенный доступ к новым API:

🔹 Apple Intelligence.
🔹 Интерактивные виджеты.
🔹 Системные жесты и анимации.
🔹 On-device AI через Core ML.


3️⃣ Высокая производительность:

Нативные приложения работают на 20-30% быстрее Flutter-аналогов благодаря прямому доступу к системным ресурсам.


Ограничения кроссплатформенных решений:

🔸 Задержки обновлений: поддержка новых функций iOS появляется с опозданием на 6-12 месяцев.
🔸 Костыли и обертки: для интеграции с системными API требуются мосты и плагины.
🔸 Визуальные компромиссы: Liquid Glass и кастомные анимации сложно реализовать.
🔸 Рост техдолга: поддержка двух платформ усложняет архитектуру.


Альтернатива — Kotlin Multiplatform, но с нюансами.

Kotlin Multiplatform (KMP) может быть компромиссом для проектов, где критична экономия без полной потери качества:

🔹 Общая бизнес-логика на Kotlin.
🔹 Нативные UI на SwiftUI и Jetpack Compose.
🔹 Снижение затрат на 20-40% без ущерба UX.

НО: даже KMP не даёт 100% преимуществ чистой нативной разработки:

🔸 Задержки с поддержкой новых API iOS: Swift-экосистема обновляется быстрее, чем KMP-компоненты.
🔸 Сложность отладки: бизнес-логика в KMP + нативный UI = два слоя для диагностики проблем.
🔸 Зависимость от JetBrains и Google: в отличие от нативного Swift, который полностью контролируется Apple.
🔸 Ограниченный доступ к iOS-специфичным функциям: особенно в первые месяцы после релиза новой iOS.


💡 Вывод:

iOS 26 сделала нативную разработку не просто выбором, а необходимостью для продуктов, которые хотят оставаться конкурентоспособными. Хотя Flutter остается вариантом для MVP, для долгосрочных проектов с высокими требованиями к UX и производительности нативный стек — самое верное решение.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥26👍143🗿3🤝11
🔨 iOS 26: как отключить Liquid Glass в iOS-приложениях.

С выходом iOS 26 многие разработчики столкнулись с необходимостью адаптации под новый дизайн-систему Liquid Glass. Но что делать, если приложение ещё не готово к переходу? Рассказываю простое решение.


⚙️ Отключение Liquid Glass:

Добавьте в ваш Info.plist параметр UIDesignRequiresCompatibility со значением YES.

Это заставит приложение использовать старую дизайн-систему вместо Liquid Glass, даже на iOS 26.


⚠️ Важные ограничения:

🔸 Это временное решение, Apple планирует убрать эту опцию в iOS 27.
🔸 Не влияет на новые API, только на визуальное оформление.
🔸 Тестирование обязательно, некоторые элементы могут выглядеть иначе.


💡 Вывод:

Временное отключение Liquid Glass — это спасательный круг для приложений, которые не успели адаптироваться к iOS 26, но не стоит воспринимать это как постоянное решение. Начинайте работу над поддержкой новой дизайн-системы, которая уже стала основной.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
🙏25👍189🔥2🤯21🤝1
🔢 Generics и Protocols: пишем код на Swift профессионально.

Если вы пишете на Swift, но не используете Generics и Protocols на полную, то вы теряете главные преимущества языка. Эти инструменты превращают код из простого набора инструкций в гибкую и безопасную систему.


1️⃣ Generics: пишем код один раз, используем везде.

Дженерики — это параметрический полиморфизм. Проще говоря, мы пишем функцию или тип один раз, а работаем с разными типами данных.

Простой пример:


func swapValues<T>(_ a: inout T, _ b: inout T) {
let temp = a
a = b
b = temp
}

var x = 10
var y = 20
swapValues(&x, &y) // Работает с Int

var s1 = "Hello"
var s2 = "World"
swapValues(&s1, &s2) // Работает с String


Ограничения generic-ов:


// Проблема: нельзя складывать любой тип данных
func sum<T>(_ a: T, _ b: T) -> T {
return a + b // Ошибка: Binary operator '+' cannot be applied
}

// Решение: сообщаем компилятору что T должен быть числом
func sum<T: Numeric>(_ a: T, _ b: T) -> T {
return a + b // Работает с любыми числами
}


Пример с протоколом:


protocol Identifiable {
var id: Int { get }
}

struct User: Identifiable {
let id: Int
let name: String
}

class DataService<T: Identifiable> {
private var storage: [Int: T] = [:]

func save(_ item: T) {
storage[item.id] = item
}
}


Использование where для сложных ограничений:


func process<T>(_ value: T) where T: Identifiable, T: Equatable {
// value имеет и id, и может сравниваться
}



2️⃣ Protocols: контракты для ваших типов.

Протоколы определяют требования, которым должны соответствовать типы. Это как чертеж для класса или структуры.

Простой пример:


protocol Drawable {
func draw()
}

struct Circle: Drawable {
func draw() {
print("Рисуем круг")
}
}

struct Square: Drawable {
func draw() {
print("Рисуем квадрат")
}
}

let shapes: [Drawable] = [Circle(), Square()]
shapes.forEach { $0.draw() }


Расширения протоколов:


extension Drawable {
// Теперь можно использовать реализацию по умолчанию
func draw() {
print("Рисуем что-то")
}
}



3️⃣ Associated Types: протоколы как дженерики.

Иногда нужно, чтобы протокол работал с разными типами данных, но мы заранее не знаем, с какими именно. Для этого используют associatedtype — это как заглушка для типа, которую заполнят при реализации.

Простой пример:


protocol Storage {
associatedtype Item
var items: [Item] { get set }
func add(_ item: Item)
}

class StringStorage: Storage {
typealias Item = String // Задаем тип
var items: [String] = []

func add(_ item: String) {
items.append(item)
}
}

class IntStorage: Storage {
var items: [Int] = [] // Компилятор сам определит тип

func add(_ item: Int) {
items.append(item)
}
}


Пример с ограничениями:


protocol ComparableStorage {
associatedtype Item: Comparable // Только сравниваемые типы
func isFirstItemGreater() -> Bool
}

class NumberStorage: ComparableStorage {
var items: [Int] = [5, 2, 8]

func isFirstItemGreater() -> Bool {
return items[0] > items[1] // Можем сравнивать
}
}


Что дает associatedtype:

🔹 Гибкость: один протокол для разных типов.
🔹 Безопасность: компилятор следит за типами.
🔹 Четкость: ясно, какие данные ожидаются.

Главное: associatedtype делает протоколы по-настоящему универсальными, позволяя им работать с любыми типами данных, сохраняя при этом полную типобезопасность.


⚠️ Как начать использовать Generics и Protocols эффективно:

🔸 Найдите повторяющийся код: где вы копируете логику для разных типов.
🔸 Определите общее поведение: что общего у ваших объектов.
🔸 Выносите в протоколы: создайте контракты для похожих объектов.
🔸 Добавляйте generics: делайте код универсальным.


💡 Вывод:

Generics и Protocols это не просто синтаксис, а способ мышления. Они превращают Swift из просто языка в инструмент для создания надежных и масштабируемых систем.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
2417👍42🔥1🙏1
👨‍💻 Что на самом деле мотивирует разработчика: три фактора, которые важнее зарплаты.

Всем привет! Сегодня хочу порассуждать на тему, которая всплывает у каждого разработчика, когда приходит время менять работу. Что на самом деле определяет, будет ли нам комфортно и интересно на новом месте? Часто все сводится к обсуждению зарплаты, но я уверен, что есть факторы куда важнее. Давайте разберемся.


🔹 Люди, с которыми ты проводишь 8 часов в день.

Можно работать над самым прорывным продуктом в мире, но если команда разобщена, а атмосфера токсична, желание творить быстро испарится. Сильная команда это не просто набор талантливых инженеров. Это в первую очередь культура взаимопомощи, доверия и открытости. В такой среде не страшно задавать «глупые» вопросы, предлагать смелые идеи и признаваться в ошибках. Именно это позволяет быстро расти. Я бы предпочел присоединиться к сильной команде со средним продуктом, чем к хаотичной команде с гениальной идеей. Первая научит тебя большему и сбережет ментальное здоровье.


🔹 Руководитель как твой личный навигатор.

Руководитель это человек, который определяет твой повседневный опыт работы. Хороший менеджер не просто ставит задачи. Он видит твой потенциал, помогает строить карьерный путь, дает конструктивную обратную связь и, что немаловажно, прикрывает твой тыл от корпоративных бурь. Он превращает препятствия в задачи, которые можно решить. Для меня совпадение по ценностям и видению с будущим руководителем часто перевешивает дополнительные 20% к окладу. Потому что с плохим менеджером эти деньги будут стоить тебе слишком дорого, в виде стресса и выгорания.


🔹 Продукт, который зажигает, а не просто платит.

Даже в лучшей команде с идеальным менеджером может не хватить мотивации, если продукт сам по себе не вызывает интереса. Речь не только о «спасе мира». Важно, чтобы продукт был качественным, с продуманной архитектурой, а не вечным MVP, который постоянно горит. Когда ты видишь, что твоя работа имеет смысл, что ею пользуются и ценят, это дает совершенно иной уровень энергии. Работа над скучным, нестабильным или бессмысленным продуктом быстро приводит к цинизму и апатии, какую бы зарплату тебе ни платили.


💡 Вывод:

Высокий оффер это отлично, но это краткосрочный стимул. Эйфория от новой зарплаты проходит через несколько месяцев, и на первое место выходят именно те факторы, о которых я написал: атмосфера в команде, адекватность руководства и интерес к продукту. Осознанный выбор, где ты оцениваешь все эти «неочевидные» вещи это инвестиция в свое профессиональное и эмоциональное благополучие на годы вперед. Не позволяйте цифре в оффере затмить те сигналы, которые действительно влияют на качество вашей жизни.

А что для вас было главным фактором на последнем месте работы? Делитесь в комментариях!


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
22👍15👀4🤯11
🔢 Swift Concurrency: правильное использование [weak self] в задачах.

Всем привет! Сегодня разберемся с темой, которая вызывает много вопросов при переходе на Swift Concurrency: как правильно использовать [weak self] в Task.

Если вы работали с completion handlers, то у вас уже выработался рефлекс, почти в каждое замыкание добавлять [weak self] и делать классический guard let self. Кажется логичным перенести этот подход и в Task:


Task { [weak self] in
guard let self else { return }

let data = await loadData()
...
}


Но вот в чем проблема: этот код не предотвращает утечку памяти так, как вы ожидаете.


⚠️ Почему это происходит:

Task начинает выполнение практически мгновенно после создания. Вероятность того, что за микросекунды между созданием Task и первой строчкой его кода self будет освобожден крайне мала.

Когда вы делаете guard let self, вы создаете сильную ссылку на объект. Теперь Task будет удерживать self до своего завершения, до окончания всех await вызовов. Это эквивалентно тому, если бы вы в старом коде с completion handlers написали просто self.loadData() без всякого [weak self].


🤔 Когда это действительно становится проблемой?

Представьте долгоиграющую задачу, например, загрузку данных постранично:


Task { [weak self] in
guard let self else { return } // Проблема здесь

var hasMorePages = true
while hasMorePages {
let page = await fetchNextPage()
hasMorePages = !page.isLastPage
}
}


Если пользователь уйдет с экрана, self не сможет освободиться, потому что Task продолжит свою работу и удерживает его до окончания цикла.


Правильное решение:

Вместо немедленного разворачивания self, делайте это точечно, непосредственно перед использованием:


Task { [weak self] in
var hasMorePages = true
while hasMorePages {
// Проверяем self на каждой итерации
guard let self else {
hasMorePages = false
break
}

let page = await self.fetchNextPage()
hasMorePages = !page.isLastPage
}
}


Теперь сильная ссылка на self создается только на время одной итерации цикла. Если self освободится, цикл немедленно завершается.


⚡️ Рекомендации:

🔸 Не всегда нужно [weak self]: для коротких Task это часто избыточно.
🔸 Избегайте guard let self в начале Task: это не дает преимуществ, но может продлить жизнь объекта.
🔸 Разворачивайте self непосредственно перед использованием: минимизируйте время удержания сильной ссылки.
🔸 Рассмотрите захват конкретных свойств: если вам нужен не весь self, а только некоторые его свойства, захватите их отдельно.


💡 Вывод:

Главное понимать, что механизм работы Task отличается от обычных замыканий, и слепое копирование старых паттернов может привести к неожиданным результатам.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍24154🔥1🙏1👀1
🔢 Что изменилось в работе со строками в Swift 6.2

Всем привет! Swift 6.2 принес нам небольшие, но очень приятные улучшения в работе со строками, которое многие давно ждали.


Какая была проблема?

До Swift 6.2 при интерполяции опциональных значений мы постоянно сталкивались с надоедливым ворнингом:

let age: Int? = nil

print("Your age: \(age)")
// String interpolation produces a debug description for an optional value


Компилятор предлагал два неидеальных решения:

🔸 String(describing:) - выводил nil, что некрасиво для пользователя.
🔸 Оператор ?? - требовал значение того же типа, что не всегда удобно.

let age: Int? = nil

// Некрасиво
Text("Your age: \(String(describing: age))") // Your age: nil

// Не всегда уместно
Text("Your age: \(age ?? 0)") // Your age: 0, но 0 может быть некорректным!



Что изменилось в Swift 6.2:

Теперь можно использовать параметр default прямо в интерполяции:

let age: Int? = nil

print("Your age: \(age, default: "not specified")") // Your age: not specified



Особенно удобно в SwiftUI:

struct ProfileView: View {
let username: String?
let level: Int?

var body: some View {
VStack {
Text("Username: \(username, default: "Guest")")
Text("Level: \(level, default: "Unknown")")
}
}
}



Что еще важно знать:

🔸 Тип значения не важен: default всегда принимает строку.
🔸 Работает с любыми опционалами: Int?, String?, Bool? и т.д.
🔸 Проверки на этапе компиляции: нет влияния на производительность.


Есть ограничение: к сожалению не работает с LocalizedStringKey.


💡 Мое мнение:

Это одно из тех небольших улучшений, которые делают повседневную разработку удобнее. Больше не нужно выбирать между ворнингами компилятора и некрасивым выводом nil в интерфейсе.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
125👍18🔥4🙏11
👨‍💻 Неожиданный тренд 2025 года: некоторые компании заменяют сеньоров на джунов.

Всем привет! Сегодня хочу обсудить тренд, который может показаться парадоксальным: в 2025 году некоторые компании сознательно заменяют опытных разработчиков начинающими. Да, вы не ослышались, джуны становятся более востребованными, чем сеньоры в определенных сценариях.


Парадокс рынка труда.

Если посмотреть на статистику безработицы в США и Европе, становится ясно: молодым специалистам действительно сложно найти работу. Но причина не только в том, что ИИ забирает начинающие позиции. Оказалось, что искусственный интеллект в первую очередь бьет по… опытным разработчикам.


Почему опыт стал проблемой?

Сеньоры и мидлы это сформировавшиеся специалисты с устоявшимися подходами к работе. У них есть:

🔸 Четкое мнение об архитектуре проектов.
🔸 Привычный набор инструментов и технологий.
🔸 Собственные стандарты кодирования.

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


Гибкость vs опыт: что ценнее?

Некоторые компании пришли к выводу: лучше взять джуна, который:

🔸 Не боится экспериментировать с ИИ.
🔸 Готов быстро осваивать новые инструменты.
🔸 Не имеет предубеждений против «новомодных» технологий.
🔸 Обходится компании дешевле.

И обучить его недостающим навыкам проще, чем переучивать сеньора, который подсознательно сопротивляется изменениям.


Рекомендации.

Если вы опытный разработчик:

🔹 Не игнорируйте ИИ-инструменты, осваивайте их постепенно.
🔹 Будьте готовы менять рабочие процессы, гибкость стала ключевым навыком.
🔹 Учитесь работать в тандеме с ИИ, а не против него.

Если вы джун:

🔹 Ваше умение быстро обучаться это главное преимущество.
🔹 Осваивайте ИИ-инструменты с самого начала карьеры.
🔹 Не бойтесь предлагать новые подходы, компании это ценят.


💡 Личное наблюдение:

Я вижу, как многие опытные коллеги совершают одну ошибку: считают ИИ временной модой. Но это не так, это фундаментальное изменение индустрии. Те, кто успеет адаптироваться, останутся востребованными. Остальные рискуют оказаться за бортом, несмотря на весь свой опыт.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍21🤯14👀11🤔41🙏1
🔢 Swift Concurrency: как Executors и Actors управляют потоками.

Разберем как на самом деле работают потоки в Swift Concurrency. Если вы думаете, что async/await — это просто синтаксический сахар, приготовьтесь удивляться. Под капотом скрывается мощная система управления задачами через Executors и Actors.


Из чего состоит Swift Concurrency:

🔸 Task: единица асинхронной работы (как поток для синхронных функций).
🔸 Job: часть задачи между точками await (suspension points).
🔸 Executor: планировщик, который распределяет Job по потокам.
🔸 Cooperative Thread Pool: пул потоков (число = числу ядер устройства).


Типы Executors:

🔸 Global Concurrent Executor: дефолтный, распределяет задачи по потокам из пула.
🔸 Serial Executors: для акторов, выполняет задачи последовательно.
🔸 Main Actor Executor: специальный для главного потока.


Пример кастомного Executor:


// Создаем свой планировщик
final class CustomExecutor: TaskExecutor {
func enqueue(_ job: consuming ExecutorJob) {
print("Запускаем задачу на потоке: \(Thread.current)")
job.runSynchronously(on: asUnownedTaskExecutor())
}

func asUnownedTaskExecutor() -> UnownedTaskExecutor {
UnownedTaskExecutor(ordinary: self)
}
}

// Использование
Task(executorPreference: CustomExecutor()) {
print("Выполняем работу")
try await Task.sleep(for: .seconds(1))
print("Завершаем работу")
}



Actors: безопасность данных.

Акторы защищают от гонки данных, выполняя методы последовательно:


actor SafeCounter {
private var count = 0

func increment() {
count += 1
print("Текущее значение: \(count)")
}
}

// Использование
let counter = SafeCounter()

Task {
await counter.increment() // Безопасный доступ
}



Как работает последовательность.

Даже при параллельных вызовах актор гарантирует порядок:


await withTaskGroup { group in
for i in 0..<5 {
group.addTask { await counter.increment() }
}
}
// Вывод всегда будет: 1, 2, 3, 4, 5



Global Actors.

@MainActor вы уже знаете, но можно создавать и свои глобальные акторы:


@globalActor
actor NetworkActor {
static let shared = NetworkActor() // Единый экземпляр на все приложение
}

@NetworkActor
func fetchData() async -> Data {
// Все вызовы этого метода будут последовательными
// даже из разных частей приложения!
}

@NetworkActor
class ApiService {
// Все методы класса будут автоматически изолированы
func getUser() async -> User {
}
}


Зачем это нужно, спросите вы. Чтобы разные функции и классы использовали один общий актор. Например:

🔸 Все сетевые запросы через один NetworkActor
🔸 Все операции с базой данных через DatabaseActor
🔸 Все аналитические события через AnalyticsActor


Важные особенности:

🔸 Потоки не блокируются: await освобождает поток для других задач.
🔸 Автоматическое планирование: система сама выбирает оптимальный поток.
🔸 Безопасность по умолчанию: компилятор следит за изоляцией данных.


Когда использовать:

🔹 Global Concurrent: для независимых задач.
🔹 Serial Executor: когда важен порядок выполнения.
🔹 Main Actor: для работы с UI.
🔹 Custom Executors: для специальных требований к планированию.


💡 Вывод:

Swift Concurrency это не просто async/await, а целая экосистема для безопасной многопоточности. Понимание работы Executors и Actors поможет писать более эффективный и надежный код.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍24126🔥4🙏31
📱 Революция в Apple: почему iOS переписывают на Rust.

Всем привет! Пока мы спорим о SwiftUI и async/await, в компании Apple происходит тихая революция. Оказывается, компания постепенно переписывает ключевые компоненты iOS и делает это не на Swift. Все указывает на Rust - язык, который становится новым фундаментом операционной системы.


Что происходит на самом деле?

Если посмотреть на вакансии Apple за последние годы, становится ясно: компания активно ищет инженеров с опытом работы с Rust. Речь идет о системных компонентах:

🔹 Управление памятью.
🔹 Безопасность и криптография.
🔹 Низкоуровневые фреймворки.
🔹 Драйверы и ядро системы.


Почему Swift не подходит для этих задач?

Swift - прекрасный язык для разработки приложений, но у него есть ограничения:

🔹 Не идеален для системного программирования.
🔹 Работа с памятью через C/Obj-C оставляет уязвимости.
🔹 Модель многопоточности уступает Rust в безопасности.


Преимущества Rust для Apple:

🔹 Безопасность памяти: компилятор предотвращает целый класс уязвимостей.
🔹 Производительность: сравнима с C++, но без головной боли.
🔹 Бесстрашная многопоточность: гонки данных обнаруживаются на этапе компиляции.
🔹 Интероперабельность: легко интегрируется с существующим C-кодом.


Что это значит для нас, разработчиков?

В краткосрочной перспективе ничего не изменится:

🔹 SwiftUI и UIKit остаются основными фреймворками.
🔹 Swift продолжит развиваться.
🔹 API для приложений не поменяются.

Но в долгосрочной перспективе:

🔹 Стабильность: меньше падений из-за низкоуровневых ошибок.
🔹 Безопасность: уменьшится количество уязвимостей нулевого дня.
🔹 Производительность: системные компоненты станут эффективнее.


💡 Мое мнение:

Apple не заменяет Swift, а дополняет его правильным инструментом. Swift остается для высокоуровневых задач, в то время как Rust возмет на ответственность за низкоуровневые компоненты, где критически важна безопасность.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2516👍4🤔4👏21
📱 Правда о вайбкодинге: почему быстрые решения убивают ваш профессиональный рост.

Всем привет! Сегодня хочу поговорить об опасной тенденции, которая захватила мир разработки - vibe coding. Это когда ты быстро переключаешься между вкладками, копируешь код из ChatGPT, видишь, что все компилируется, и чувствуешь себя продуктивным. Но на самом деле ты не понимаешь, что происходит.


Что не так с вайбкодингом?

Представьте: вы едете домой и разговариваете по телефону. Через час вы не помните ни дороги, ни поворотов, ни светофоров. Точно так же работает вайбкодинг, все происходит как в тумане.


Типичная ситуация:

Разработчик за вечер создал несколько приложений с помощью ChatGPT. В одном была сложная логика расчетов. Код работал идеально, но разработчик не мог объяснить, как он работает. Это как собрать мебель по инструкции, не понимая, зачем нужны детали.


Почему это опасно для карьеры:

🔸 Вы не становитесь экспертом: знание предметной области часто важнее технических навыков.
🔸 Технический долг растет как снежный ком: вы не понимаете, какие проблемы создаете.
🔸 Вас легко заменить: любой может скопировать код из AI, но не каждый может его осмысленно улучшить.


Что важнее: скорость или понимание?

ИИ-инструменты это мощные помощники. Но когда они заменяют ваше мышление, любопытство и желание разбираться - вы перестаете расти.

Настоящий прогресс приходит через:

🔸 Борьбу с сложными ошибками.
🔸 Понимание КАК и ПОЧЕМУ что-то работает.
🔸 Глубокое погружение в проблему.


Правила осознанного использования ИИ:

Джуны, которые осмысленно работают с ИИ, растут быстрее, чем мидлы, просто копирующие код. Разница в подходе: первые используют ИИ как инструмент, вторые как костыль.

🔸 Используйте ChatGPT для рутины и изучения новых подходов.
🔸 Всегда анализируйте сгенерированный код перед использованием.
🔸 Задавайте вопросы «почему это работает?» и «как можно улучшить?».
🔸 Сохраняйте баланс между скоростью и качеством.


💡 Вывод:

Vibe coding хорош для прототипов и MVP, но только при очень вдумчивом использовании. Если вы не понимаете код, который пишете, вы не можете ему доверять. А если не можете доверять, то не можете нести за него ответственность.


А как вы используете ИИ в работе?


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2419👀7🔥4🤔2🤯2
🔢 Swift Concurrency: что на самом деле делает компилятор?

Swift Concurrency - это не просто синтаксический сахар. Под капотом происходит сложная трансформация кода, управляемая компилятором и рантаймом. Давайте разберём ключевые компоненты системы.


Компилятор и State Machine.

Когда компилятор встречает async функцию, он разбивает ее на состояния (state machine). Каждый await становится точкой приостановки, между которыми код делится на блоки.


func fetchData() async -> Data {
let data = await downloadData()
let processedData = await process(data)
return processedData
}



Suspension Points (Точки приостановки).

Каждый await это место, где:

🔹 Стек сохраняется в кучу (heap).
🔹 Поток освобождается для других задач.
🔹 Создаётся continuation (информация для возобновления).

Особенности:

🔹 Приостановка не блокирует поток (в отличие от DispatchQueue).
🔹 Swift Runtime управляет жизненным циклом данных.


Continuation (Продолжение).

Это объект, который хранит:

🔹 Точку возобновления (какой await был последним).
🔹 Локальные переменные.
🔹 Что делать после получения результата.

Пример:


withCheckedContinuation { continuation in
someAsyncOperation { result in
continuation.resume(returning: result)
}
}



Executor (Исполнитель).

Определяет где и когда выполнять код после await. Могут быть следующие варианты:

🔹 Главным потоком (для MainActor).
🔹 Глобальным исполнителем (для обычных async функций).
🔹 Кастомным (для акторов).

Особенности:

🔹 Если функция запущена на MainActor, продолжение тоже выполнится на нём.
🔹 Глобальные функции используют кооперативный пул потоков.


Co-operative Thread Pool (Пул потоков).

Особенности:

🔹 Фиксированное количество потоков (обычно = числу ядер CPU).
🔹 Потоки не блокируются: при await они переключаются на другие задачи.
🔹 Управляется Swift Runtime, а не операционной системой.

Почему это эффективно?

🔹 Нет накладных расходов на создание потоков.
🔹 Автоматическая балансировка нагрузки.


Как это работает вместе?

🔹 Мы вызываем async функцию, после чего компилятор создаёт state machine.
🔹 При первом await: состояние и переменные сохраняются в continuation, поток возвращается в пул.
🔹 Когда результат готов, executor решает, где возобновить выполнение.
🔹 State machine продолжает работу с последней точки.

Пример с потоками:


func loadData() async {
// 1. Выполняется на случайном потоке из пула
let data = await fetchFromNetwork() // 2. Поток освобождается
// 3. Возобновляется на том же или другом потоке
await MainActor.run {
self.data = data // 4. Гарантированно на главном потоке
}
}



💡 Вывод:

🔸 Компилятор разбивает код на состояния.
🔸 Continuation хранит прогресс выполнения.
🔸 Executor выбирает поток для возобновления.
🔸 Пул потоков обеспечивает эффективное использование CPU.

Это делает Swift Concurrency легковесным и масштабируемым, в отличие от традиционных потоков.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
2117👍9🔥3🙏32
🏋️ Android теряет свободу: новые правила верификации разработчиков по паспорту.

Хотя мое сердце принадлежит Swift и разработке под устройства Apple, я также активно занимаюсь кроссплатформенной разработкой на Flutter. Именно поэтому не могу пройти мимо важнейшей новости из мира Android, которая затронет тысячи разработчиков, включая тех, кто работает с Flutter.

Google объявила о радикальных изменениях в политике безопасности, которые могут навсегда изменить экосистему Android.


Что происходит?

С 2026 года Google вводит обязательную верификацию разработчиков по паспорту. Теперь для подписи APK-файла потребуется:

🔹 Предъявить документ, удостоверяющий личность.
🔹 Пройти проверку в Android Developer Console.
🔹 Оплатить регистрационный взнос $25.


Что это значит на практике?

Для пользователей:

🔹 Установка приложений из сторонних источников усложнится.
🔹 F-Droid, RuStore и другие альтернативные магазины могут прекратить существование.
🔹 Свобода выбора приложений значительно сократится.

Для разработчиков:

🔹 Анонимная разработка станет невозможной.
🔹 Открытые проекты и экспериментальные приложения окажутся под угрозой.
🔹 Российские разработчики могут столкнуться с дополнительными сложностями из-за санкций.


Почему это важно?

Компания Google движется к модели закрытой экосистемы, похожей на Apple. Компания объясняет это борьбой с вредоносным ПО, но на деле получается монополизация рынка.


Под угрозой оказываются:

🔹 F-Droid: крупнейший магазин открытого ПО.
🔹 RuStore: российская альтернатива Google Play.
🔹 Независимые разработчики: те, кто не хочет связываться с Google.
🔹 Опенсорс-проекты: многие из них существуют на энтузиазме.


Технические детали:

Новая система проверки подписи может быть внедрена на уровне ядра Android. Это значит, что неподписанные приложения просто не запустятся на сертифицированных устройствах.


💡 Вывод:

Android постепенно превращается в iOS. Если вы цените свободу выбора и открытость платформы, то сейчас самое время высказать свою позицию. Возможно, массовые обращения разработчиков смогут повлиять на решение Google.

Однако важно понимать, что новые требования не затронут AOSP (Android Open Source Project) и основанные на нем форки. Это создает уникальную ситуацию, при которой Google может потерять свою монополию на Android. Все больше производителей начнут переходить на альтернативные операционные системы, такие как HarmonyOS от Huawei и HyperOS от Xiaomi.


А что думаете вы? Считаете ли вы такие меры оправданными для безопасности или это чрезмерный контроль?


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
😁14🤯11👍7🤔4👀32
🔢 Enums vs Structs в Swift: когда что использовать.

При разработке на Swift часто встаёт вопрос: выбрать перечисления или структуры? Давайте разберёмся, когда какой тип подходит лучше.


🔸 Когда выбирать Enum:

Сейчас рассмотрим несколько вариантов, когда стоит выбрать перечисление:


Конечный набор состояний.

Enums отлично подходят, когда у тебя есть чётко определённые варианты, которые не будут меняться. Классический пример - состояние загрузки:


enum LoadingState {
case idle
case loading
case success(Data)
case failure(Error)
}


Преимущество: компилятор заставит обработать все кейсы в switch, что исключит ошибки.


Взаимоисключающие состояния.

Когда объект может находиться только в одном из четких состояний:


enum AuthState {
case loggedIn(User)
case loggedOut
case guest
}


Здесь невозможно одновременно быть авторизованным и гостем - это гарантирует типобезопасность.


Сопоставление с образцом (pattern matching).

Enums идеальны, когда нужно разное поведение для разных состояний:


switch authState {
case .loggedIn(let user): showProfile(user)
case .loggedOut: showLogin()
case .guest: showLimitedAccess()
}



🔸 Когда Struct работает лучше:

Рассмотрим несколько вариантов, когда стоит выбрать структуру:


Гибкость и расширяемость.

Structs позволяют создавать любые комбинации значений. Например, для тем оформления:


struct AppTheme {
var primaryColor: Color
var secondaryColor: Color
}


Можно легко добавлять новые темы без изменения существующего кода.


Конфигурации и настройки.

Когда нужно много параметров с возможностью кастомизации:


struct UserSettings {
var isDarkMode: Bool
var fontSize: CGFloat
var accentColor: Color
}


Пользователь может комбинировать параметры как угодно.


Сложные составные состояния.

Структуры могут хранить множество связанных данных:


struct NetworkState {
var isConnected: Bool
var connectionType: String
var speed: Double?
var lastError: Error?
}



Ключевые отличия:

🔹 Перечисления: обеспечивают безопасность на этапе компиляции, но ограничены фиксированным набором вариантов. Невозможно добавить новый кейс без изменения всех switch-блоков.
🔹 Структуры: дают гибкость, но требуют ручной проверки валидности данных. Нет гарантии, что все возможные значения будут обработаны.


💡 Вывод:

Выбирайте перечисления, когда работаете с фиксированным набором взаимоисключающих состояний - это даст вам безопасность на этапе компиляции и удобный pattern matching. Структуры же идеалены для гибких конфигураций и сложных данных, которые могут расширяться со временем. Главное - заранее продумать, насколько предсказуемы будут изменения в твоей модели данных. Оба инструмента мощные, просто применяются для разных задач.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
2214👍12🔥1🙏1🫡1
📱 Как я создал полноценную доску объявлений в Telegram.

После разработки приложения для отказа от вредных привычек я решил создать что-то новое и необычное для себя. Идея пришла в голову сама, после очередной блокировки без причины на самой популярной доске объявлений в нашей стране. Поэтому родилась идея: сделать удобную альтернативу, без необходимости установки лишних приложений, прямо в Telegram. Так и появился бот бесплатных объявлений: freeBuySellBot.

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


Что особенного в freeBuySellBot:

🔹 Полноценная доска объявлений прямо в Telegram: не нужно скачивать отдельное приложение.
🔹 Простая регистрация: никаких паролей и подтверждений почты.
🔹 Загрузка фото и редактирование объявлений в пару кликов.
🔹 Бесплатное поднятие объявлений раз в неделю: никаких скрытых платежей.
🔹 Удобный поиск по ключевым словам с пагинацией.
🔹 Избранное и история просмотров: не потеряете интересные предложения.
🔹 Встроенная связь с продавцом: вся коммуникация в одном месте.


Моя цель - получить интересный опыт при работе с новыми для себя технологиями и создать по-настоящему удобную площадку, где не нужно устанавливать дополнительные приложения, проходить сложные регистрации или подписываться на навязанные услуги. Бот уже помогает людям находить интересные вещи и избавляться от нужных, доказывая, что для комфортных сделок не нужны лишние сложности.

В планах добавление системы рейтинга пользователей и категорий объявлений для более удобного поиска.


Разработка:

🔹 Бот написан на JavaScript и Node.js.
🔹 Использовал фреймворк Telegraf для работы с Telegram Bot API.
🔹 База данных: SQLite для хранения пользовательских данных.


📊 На текущий момент в боте зарегистрировано более 10 тысяч человек.

🔗 Попробуйте freeBuySellBot прямо сейчас, не выходя из Telegram!


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍146🗿44😁3🔥2👏1🫡1
🔨 Оптимизация памяти: как снизить потребление памяти в iOS-приложениях.

Всем привет! Сегодня разберем одну из самых важных тем в iOS-разработке: эффективное управление памятью. Правильная работа с памятью это то, что отличает профессиональные приложения от посредственных!


Реактивный vs проактивный подход: выбор стратегии.

Существует два принципиально разных подхода к управлению памятью. Большинство команд, особенно в условиях сжатых сроков, действуют реактивно: сначала выпускают продукт, а потом начинают «тушить пожары» когда пользователи жалуются на вылеты и тормоза. Распространенный случай, когда одна-единственная анимация Lottie умудрялась «съедать» целый гигабайт памяти только потому, что дизайнер экспортировал все кадры как отдельные bitmap-изображения!

Однако есть более зрелый подход: проактивная разработка. Это философия, при которой вы с самого начала проекта закладываете правильные практики:

🔹 Систематически используете defer для гарантированной очистки ресурсов.
🔹 Тщательно подбираете и оптимизируете графические ассеты.
🔹 Продумываете стратегию кэширования для разных типов данных.
🔹 Осознанно выбираете между value types и reference types.
🔹 Регулярно проводите профилирование в Instruments.


Практические советы по оптимизации:


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

Золотое правило: никогда не загружайте изображения в полном разрешении если они отображаются в уменьшенном виде. Особенно это актуально для галерей и коллекций. Используйте фреймворк Image I/O для создания миниатюр, он позволяет декодировать изображения с точным контролем размера. Всегда применяйте асинхронную загрузку и не забывайте о метаданных, зачастую EXIF-данные занимают больше места чем само изображение!


Core Data и управление транзакциями.

Здесь важно найти баланс. Слишком частые сохранения создают нагрузку на диск и снижают производительность, а слишком редкие приводят к накоплению изменений в памяти. В больших транзакциях это может вылиться в десятки мегабайт! Экспериментируйте с разными стратегиями, иногда оптимальным решением оказывается batch-обработка с сохранением каждые 100-200 изменений.


Умное кэширование с NSCache.

NSCache это ваш верный союзник в борьбе за память, но важно понимать его философию. В отличие от обычных словарей, NSCache автоматически очищается при memory pressure, но только если вы правильно его настроили:

🔹 Всегда устанавливайте разумные лимиты по количеству объектов и суммарному размеру.
🔹 Используйте evictsObjectsWithDiscardedContent = true для автоматической очистки.
🔹 Помните что ключи должны быть наследниками NSObject.
🔹 Для сложных объектов реализуйте протокол NSDiscardableContent.


Lazy-загрузка ваш лучший друг.

В SwiftUI обязательно используйте LazyVStack и LazyHStack вместо обычных контейнеров, они создают элементы интерфейса только при попадании в область видимости. В коде применяйте lazy var для тяжеловесных объектов которые могут не понадобиться, например, кэшированных изображений, форматировщиков дат, или сложных вычислительных объектов.


Структуры вместо классов где это возможно.

Память для структур и перечислений выделяется на стеке и не создают проблем с подсчетом ссылок. Для моделей данных, конфигураций, параметров отображения, везде где не требуется передавать ссылку на объект, используйте value types. Это не только упрощает многопоточность, но и делает потребление памяти более предсказуемым.


Используйте инструменты отладки.

Memory Graph Debugger в Xcode это мощнейший инструмент который показывает не только утечки, но и циклические ссылки. Научитесь читать его отчеты как открытую книгу! Не забывайте про Allocations в Instruments, он помогает отслеживать общее потребление, а Leaks специализируется именно на утечках памяти.


💡 Вывод:

Самое важное: начать думать о памяти с самого начала проекта. Реактивный подход всегда оказывается дороже и болезненнее. Регулярное профилирование, правильный выбор инструментов и понимание «под капотом» - вот ключ к созданию стабильных и отзывчивых приложений.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
🙏25👍1613🔥3🤝321
👨‍💻 Советы, которые помогли бы мне в начале карьеры в IT.

За годы работы в IT я собрал советы, которые значительно ускорили бы мне рост на старте карьеры.


Никогда не поздно сменить направление.

Многие остаются в нелюбимом направлении из-за комфортной зарплаты или страха начать заново. Но самый большой рост происходит именно тогда, когда вы слушаете себя, а не внешние обстоятельства. Если чувствуете, что перестали развиваться - это знак, что пора что-то менять.

Я начинал с web-разработки на PHP, но со временем понял, что мобильная разработка для меня гораздо интереснее.


Инструменты меняются, принципы остаются.

Не зацикливайтесь на конкретных технологиях. Языки и фреймворки приходят и уходят, а фундаментальные принципы, такие как архитектура, алгоритмы, проектирование остаются актуальными годами. Умение адаптироваться ценнее знания конкретного стека.


Командная работа - вот настоящая суперсила.

Современная разработка невозможна в одиночку. Системы контроля версий, ревью кода, CI/CD - это не просто инструменты, а необходимость. Чем раньше вы освоите культуру совместной работы, тем быстрее будете расти.


Умение искать информацию важнее запоминания.

Не пытайтесь держать все в голове. Ключевой навык это быстро находить и фильтровать информацию. Правильный запрос в поисковике или чат-боте часто ценнее часа чтения документации.


Практика единственный путь к мастерству.

Теория дает основу, но настоящие навыки приходят только с практикой. Не бойтесь экспериментировать и делать ошибки, именно так формируется настоящий опыт.


Баланс не роскошь, а необходимость.

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


Широкий взгляд важнее узкой специализация.

Программирование это не только написание кода. Понимание бизнес-контекста, коммуникация с командой, умение работать с требованиями часто важнее технических деталей.


Незнание чего-либо - это нормально.

В IT невозможно знать все, технологии развиваются слишком быстро. Нормальное восприятие состояния «я этого не знаю, но научусь» - ключ к постоянному росту.


Делайте только то, что вам нравится.

Заставлять себя работать это путь в никуда. Мозг саботирует неинтересные задачи. Найдите то, что приносит удовольствие, делайте это хорошо, получайте признание = любите работу еще больше.


💡 Вывод:

Карьера в IT - это марафон, а не спринт, где важно сохранять гибкость мышления и готовность к изменениям. Самые успешные специалисты не те, кто знает все, а те, кто умеет адаптироваться, сотрудничать и постоянно учиться. Найдите то, что приносит вам искреннее удовольствие, и не бойтесь менять направление, именно это приводит к настоящему профессиональному удовлетворению и росту.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍30179🔥5🙏4👏2👀1
🔨 Ошибки iOS-разработчиков при работе с Derived Data.

Всем привет! Сегодня поговорим о Derived Data - одной из самых загадочных, но важных папок в жизни iOS-разработчика. Хотя мы редко взаимодействуем с ней напрямую, именно здесь Xcode хранит кэш для ускорения сборки проектов.

Обсудим основные ошибки, которые совершают разработчики при работе с Derived Data:


Непонимание предназначения папки.

Derived Data это не просто папка для мусора. Здесь хранится:

🔹 Кэш компиляции модулей.
🔹 Информация о Swift packages.
🔹 Символы для отладки.
🔹 Собранные бинарные файлы.

Папки с суффиксом .noindex (ModuleCache, SDKStatCaches, SymbolCache) лучше не трогать без необходимости. Хотя иногда их очистка помогает решить проблемы с симулятором, в 90% случаев достаточно работать только с папкой конкретного проекта.


Ручной поиск папки.

Не ищите Derived Data вручную через Finder! Есть простой способ:
Xcode -> Settings -> Locations -> Derived Data

Маленькая синяя стрелка - это кнопка, которая мгновенно откроет папку в Finder.


Удаление папки Derived Data.

Классическая ошибка, когда Xcode «заглючил», многие удаляют всю папку Derived Data. Правильный подход:

🔹 Сбросить настройки симулятора.
🔹 Сделать Clean Build в Xcode.
🔹 Удалить ТОЛЬКО папку проблемного проекта.

Удаляя всю Derived Data, вы заставляете Xcode пересобирать ВСЕ проекты с нуля, что может занять много времени.


Игнорирование метрик сборки.

Это особенно критично для команд. Представьте:

🔹 Сборка замедлилась на 30 секунд.
🔹 В команде 20 разработчиков.
🔹 Каждый делает 10 сборок в день.

Итого: команда теряет полтора часа в день!

Решение: использование инструменты вроде RocketSim Team Insights для мониторинга:

🔹 Время типичной и максимальной сборки.
🔹 Разницу между чистыми и инкрементальными сборками.
🔹 Влияние версий Xcode и macOS на производительность.

Эти данные помогают обосновать покупку новых MacBook для команды, иногда это дает до 30% прироста скорости!


Отсутствие анализа сборок.

В подпапках проекта в Derived Data лежит собранное приложение. Если заглянуть внутрь (Show Package Contents), то можно обнаружить следующие папки и ресурсы:

🔹 Resources: могут содержать неиспользуемые ассеты.
🔹 Frameworks: иногда там остаются ненужные зависимости.
🔹 Bundles: сторонние библиотеки могут добавлять лишние ресурсы.

Это напрямую влияет на размер приложения! Однажды нам удалось уменьшить размер приложения на 70 МБ, благодаря удалению неиспользуемых ресурсов и лишних библиотек.


Неиспользование кэша для CI/CD.

Многие команды напрасно игнорируют Derived Data в процессах непрерывной интеграции. При каждой сборке на CI-сервере Xcode заново компилирует все зависимости. Правильный подход: кэшировать папку Derived Data между сборками, особенно:

🔹 Кэш компиляции Swift Packages.
🔹 Скомпилированные модули зависимостей.
🔹 Кэш Asset Catalog.


Игнорирование проблем с инкрементальной сборкой.

Если вы замечаете, что Xcode постоянно пересобирает файлы, которые не менялись - проблема часто кроется в Derived Data. Типичные причины:

🔹 Поврежденный кэш модулей.
🔹 Неправильные временные метки файлов.
🔹 Конфликт версий Swift компилятора.

Решение: использовать флаг -driver-show-incremental в настройках сборки, чтобы увидеть, что именно заставляет Xcode пересобирать файлы. Это помогает выявить проблемы с зависимостями и оптимизировать структуру проекта.


💡 Вывод:

Derived Data не враг, а мощный инструмент для оптимизации процесса разработки. Правильная работа с ним экономит часы и нервы.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
2216🔥7👍4😁2🙏22
👨‍💻 Когда логи бессильны: истории о самых неочевидных багах в мобильной разработке.

Всем привет! Сегодня хочу поговорить о самой изматывающей части работы разработчика: поиске багов, которые возникают в самых неожиданных условиях. Когда проблема есть только у одного пользователя, воспроизводится раз в полгода и вообще выглядит как мистика.


Загадка с Face ID и темной темой:

Недавно мы получили странный баг-репорт: «Приложение зависает при попытке войти через Face ID». Особенность была в том, что проблема возникала только у пользователей с включенной темной темой и только на iPhone 14 Pro.

Логи показывали стандартный поток аутентификации, но при вызове Face ID приложение просто замирало. Оказалось, что кастомная анимация загрузки конфликтовала с системным модальным окном Face ID в темной теме. Система пыталась применить темную тему к нашему кастомному компоненту, что приводило к бесконечному циклу обновления UI.


Проблема с арабским языком и скроллом:

Другой интересный случай: пользователь жаловался на дергающийся скролл в списке. Особенность: устройство было настроено на арабский язык с направлением текста справа налево.

Мы тестировали приложение с английским и русским языками, но забыли про RTL-локации. Оказалось, что кастомный индикатор скролла неправильно рассчитывал позицию при RTL-раскладке, из-за чего происходило постоянное перерисовывание контента.


Режим энергосбережения как тормоз:

Классика: жалобы на тормозящее приложение, когда у телефона меньше 20% заряда и включен режим энергосбережения. Система ограничивает производительность, а пользователь винит наше приложение.


Slide Over и потерянный контент:

Еще одна история: пользователь сообщал, что в режиме Slide Over на iPad пропадает часть контента. При обычном использовании все работало идеально.

Проблема была в том, что мы не учитывали изменение safe area insets в компактном режиме. Контент просто уезжал за границы видимой области, но только при определенной ширине Slide Over.


Загадка в подвале:

Несколько лет назад к нам пришла жалоба: «Приложение не работает вообще». Никакие данные не грузятся, картинки не отображаются. По логам полная чистота. У пользователя нет аномалий, мы перепробовали все сценарии.

И тогда мы задали простой вопрос: «А где вы находились, когда это произошло?».

Ответ оказался неожиданным: «в подвале». Человек решил проверить работу приложения в под землей, где не ловил ни Wi-Fi, ни мобильный интернет. Всё встало на свои места!


💡 Что я из этого вынес:

🔸 Контекст важнее технических данных: иногда нужно спросить не «что делали?», а «где и при каких условиях?».
🔸 Логи не всесильны: они показывают только то, что мы предусмотрели.
🔸 Пользователи живут в другом мире: их сценарии использования часто отличаются от наших, тестовых.
🔸 Тестируйте неочевидные сценарии: темная тема, разные языки, специальные возможности.
🔸 Учитывайте особенности платформы: Slide Over, Split View, Picture-in-Picture.

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


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2113🔥13😁4👀32🙏1