Всім привіт! Мене звуть Андрій, мені 24 роки, я працюю Senior iOS/macOS Engineer у компанії Readdle. Я цікавлюся технологіями все своє життя, починав з Turbo Pascal в дитинстві і встиг попрацювати з embedded системами, frontend/backend розробкою та machine learning проектами.
В перший раз я познайомився з розробкою на iOS під час невеликого курсу в університеті. За місяць я опанував на той момент незнайому мені мову програмування та пройшов до інтернатури в Readdle. Методично вивчаючи нову для мене інформацію, за 4 роки роботи я досяг рівня senior інженера. Зараз я приймаю участь в співбесідах, стаю ментором для нових людей в команді, та вивчаю скіли менеджменту, щоб рухатися далі.
Мій шлях від людини без досвіду програмування на платформах Apple до поточної позиції надихнув мене проаналізувати мою методику навчання та виділити основні вектори розвитку. Я впевнений, що мій досвід виявиться корисним багатьом інженерам, які знаходяться в режимі стагнації, та не розуміють, куди рухатися далі. Я хочу поділитися методами та напрямками розвитку, разом з джерелами інформації та ідеями проектів, які допоможуть знайти натхнення та отримати різноманітний досвід.
Як вивчення різних технологій впливає на траєкторію карʼєри
Особисто я зустрівся з проблемою "професійного блоку" коли дійшов до middle рівня. На мою думку, я швидко та якісно виконував робочі задачі, без проблем фіксив баги та мав уявлення про архітектуру для нових фічей. Але я не розумів, що мене відділяє від справжнього senior інженера. Через декілька років ця проблема для мене вирішилася майже сама. Коли я нещодавно пригадав цей період, в мене виникло питання: "А що в мені змінилося?" Я зрозумів, що весь цей час я активно працював над проектами, які не були пов'язаними до моєї робочої кар'єри. Навіть після закінчення робочого часу я зазвичай продовжував програмувати та працював над своїми речами. Навички та досвід з цих проектів з часом переносився до моїх робочих процесів зовсім неочікуваними шляхами. Це дозволило мені мати досвід та експертизу за межами робочого проекту і знаходити рішення нетривіальних нових для команди проблем.
Секрет в тому, що більшість інформації щодо розробки програмного забезпечення насправді не прив'язана до конкретної мови програмування або технології. Як саме це проявляється?
-
Навіть якщо ви зараз читаєте про те, як працюють архітектури для iOS додатків, скоріше за все ви зможете знайти схожі патерни у web розробці, та навіть у embedded девайсах.
-
Знання python в контексті machine learning може дозволити швидко написати потрібний скрипт для автоматизації CI процесів в зовсім іншій галузі.
-
Основи операційних систем допоможуть зрозуміти цілий клас проблем у будь якій мові програмування. Будь яка програма написана будь якою мовою спілкується з операційною системою в однаковий спосіб.
-
Однією із моїх перших книг з програмування була Effective Java авторства Joshua Bloch. Незважаючи на те, що я не пишу на Java вже багато років, саме ця книга мені дозволила зрозуміти фундаментальні принципи ООП та зрозуміти, навіщо потрібні інтерфейси. Ці знання доречні до будь якої мови.
Для того, щоб приділяти час розробці крім робочих годин, потрібно мати натхнення на це. На мою думку найкращими інженерами стають люди, які щиро полюбляють це ремесло, та готові працювати над своїми навичками в будь який час.
Як навчитись чому завгодно
Деякі люди опановують нову інформацію значно швидше, ніж інші. При чому зазвичай не має значення конкретний характер інформації. Це може бути нова мова програмування, новий патерн або архітектура, або взагалі щось не пов'язане з розробкою, наприклад навички гри в шахи. Це спостереження мене переконало в існуванні деякого "meta-skill", а саме загальної навички навчатися чомусь новому. Я відрефлексував свій досвід навчання різним речам та помітив схожі патерни та моделі своєї поведінки. Думаю, що це заслуга університету та школи, бо під час навчання різним дисциплінам одночасно моя свідомість оптимізувала схожі патерни. Це дозволило мені швидко вчитися.
Зараз, в мене є конкретний процес навчання будь чому. Я не думаю, що цей процес є чимось інноваційним, але мені саме він відкрив можливість концентруватися на інформації та на своєму розвитку. В цьому блоці я хочу розглянути детальніше конкретні етапи цього процесу які я назвав Screening(скрінінг), Structuring (структурування) та Practice (практика).
Скрінінг
Якісне джерело інформації — важливий перший крок в опануванні нових навичок. Деякі мої рекомендації по цьому процесу:
-
Більшість інформації з будь якої теми доступна безкоштовно. Не має сенсу розглядати будь які платні курси або лекції, якщо ви не впевнені на 100%, що це унікальна інформація. Але якщо ви тільки починаєте вивчати тему, то експертизи у вас все одно не буде, і відрізнити ексклюзив від фальшивки ви не зможете.
-
Зазвичай інформація у форматі тексту більш змістовна та легка до розуміння, ніж відео матеріали. Особливо, якщо ви вмієте швидко читати. В мене з часом розвився механізм фокусу, який дозволяє швидко пропускати нерелевантну інформацію очима. З відео матеріалами це зробити неможливо, тому що інформація розтягнута по часу. Також при поверненні до джерела, простіше залишити собі закладку чи скопіювати текст, ніж шукати потрібний момент у відео.
-
З мого досвіду, англомовні ресурси знайти значно легше ніж ресурси іншими мовами. Особливо це доречно до ресурсів з розробки та технологій. Тому вміти швидко читати та розуміти англійську — це must!
-
Якщо по темі є книжки, які рекомендовані на будь яких форумах/статтях — завжди має сенс їх прочитати. Я був дуже здивований, коли дізнався, що більшість програмістів не знають книжок з програмування. Дуже багато проблем сучасного програмування вже розглянуті декади тому та є в літературі. Також книги пропонують щільну та структуровану інформацію по темі. Рекомендую почати збирати бібліотеку з книжок по різним темам, щоб мати можливість швидко знайти потрібну інформацію. В мене такою бібліотекою є проста директорія з файлами на комп'ютері.
Стуктурування
Коли я знаходжу декілька джерел, я починаю процес структуризації інформації. Він в себе включає
-
Обробку джерел інформації. Коли я читаю книгу або статтю, я помічаю важливі частини закладками або копіюю їх до заміток.
-
Кросс-референс інформації. Особливо коли тема є суб'єктивною - дуже важливо переглянути декілька можливих рішень та рекомендацій. Інформація, яка збігається в декількох різних джерелах ймовірно буде істиною. Якщо в джерелах є протиречива інформація - краще залишити рішення на потім. Коли у вас з’явиться своя експертиза з теми, можна буде вибрати більш доречне рішення.
-
Централізація знань. Щоб отримані та знайдені шматочки інформації з теми можна було обробити разом, їх треба зберегти разом. Для централізації знань я використовую Obsidian. Він безкоштовний, і markdown формат мені здається дуже зручним.
-
Збереження. Статті та корисні лінки я зазвичай зберігають в простих markdown списках. Це дозволяє швидко знаходити потрібний лінк, замість того, щоб шукати по історії. Також, якщо тема буде потрібна в майбутньому, більшість інформації в мене вже буде готова.
Практика
Тільки закріпивши інформацію практикою, ми насправді запам’ятовуємо її. Тому, кожну тему я стараюся закріпити створенням невеликих проектів. Якщо говорити конкретно про програмування — це зазвичай невеликий додаток, який демонструє вміння застосувати необхідні навички. Також, швидка практика відразу демонструє усі пусті місця в розумінні теми. В мене досить часто було уявлення, що я розумію все що треба, але після 10 хвилин імплементації я зустрічався з проблемами, про які я навіть не думав.
Для мене гарним прикладом буде вивчення архітектур UI додатків. Коли я вперше вивчав MVVM в контексті iOS розробки, мені здавалося, що архітектура проста і зрозуміла. Коли я спробував створити простий todo-list додаток, я відразу зіткнувся з пробілом в знаннях. Інформація, яку я знав, чітко казала як View спілкується з ViewModel, а ViewModel з Model. Але ніхто не казав хто кого і як має створювати! В моєму додатку була таблиця з поточними todo задачами. Чи потрібно мені робити окрему ViewModel на кожну задачу? Чи це має бути одна ViewModel на всю таблицю? А якщо мені потрібні обидві ViewModel? Хто кого створює? Ці питання відкрили для мене задачу координування компонентів в схожих архітектурах. Через деякий час, працюючи над PDF Expert, наша команда вирішила спробувати MVVM. Я зміг побудувати архітектуру та координувати команду у розробці цієї фічі. Це досвід, який я би навряд зміг би отримати без попереднього, може навіть сирого todo-додатку.
Мої рекомендації стосовно проектів:
-
Знайти натхнення та ідею. Зазвичай в мене з'являється спочатку ідея додатку, а потім я цю ідею прив'язую до напрямку розвитку. Ідея не повинна бути унікальною та взагалі мати хоч якийсь потенціал, тому що основна задача — отримати потрібний досвід. Наприклад, я хочу створити додаток для відстеження своїх звичок. Я можу сконцентруватися на архітектурі, а можу використати цю ідею щоб побудувати вражаючий user interface з анімаціями. А може мені для цього додатку потрібно зробити сервер? Може це бути гарним проектом щоб спробувати нові технології backend розробки!
-
Встановити Definition of Done («Критерії готовності»). Якщо спробувати доводити кожен проект до production, то на кожен з них треба виділити купу часу. Тому, на мою думку, треба мати конкретні ідеї щодо того, які інкременти ви хочете бачити в своєму проекті.
-
Iдеальний – ворог хорошого. У пошуку ідеального рішення проблеми можна загубити бажання рухатися вперед взагалі.
-
Мінімізувати непотрібні задачі. Чи має значення, яку дизайн палітру використовувати у додатку для вивчення архітектури? Чи систему логування? На моєму досвіді найбільш корисними виявилися проекти, сфокусовані на конкретній темі. Чим менше часу я витрачаю на важливі речі — тим більше я можу витратити на вивчення важливих.
Ідеї для напрямків
В цьому блоці я хочу розглянути 10 напрямків, які надихали саме мене на вивчення чогось нового. Багато з них мають позитивний вплив на вміння вирішувати задачі у моїй роботі.
Архітектури UI-додатків
Всі інженери, які колись працювали з UI проектами, знають про класичні патерни та архітектури організації коду. Хто з нас не чув про MVC, MVP, MVVM? На моєму досвіді прості теоретичні знання можуть дати впевненість в розробці нового проекту, але патерни, застосовані без практичного досвіду мають тенденцію втрачати свою форму при найменших змінах. Колись я був впевнений, що знаю, як працює MVVM архітектура. Але виявилося, що в мене не було досвіду спробувати її, і мої знання мали великі чорні плями. Зрозумів я це, коли спробував розробити свій невеликий додаток на MVVM. Я швидко зіткнувся з потребою координаторів та роутерів для навігації та збірки мішанини класів в готову структуру. На мою думку, найважливішим результатом досліджень різних архітектур є відсутність "найкращого" рішення. Архітектура, яка спрацювала в іншому проекті, може бути проблемною в конкретному випадку, або навіть в конкретному екрані.
Патерни проектування
Напевно всі, хто проходив співбесіди на вакансію розробника, стикався з питаннями по патернах. Здається, що багато інженерів усвідомлюють якісь конкретні патерни, але не вміють їх використовувати на практиці. Просте рішення цього питання — спробувати розробити невеликий проект, фокусуючись на конкретному патерні. В оригінальній книзі як приклад багато використовується редактор текстових документів. На моєму досвіді редактори різних документів потребують використання багатьох патернів проектування. Це може бути текстовий редактор, або редактор зображень, а може навіть програма для малювання діаграм.
Тестування
Тестування коду — це основа стабільності кодових баз. І хоча ідея звучить досить просто — "треба писати тести!", написати корисні тести може бути нетривіальною задачею. Основна проблема є в тому, що підтримка тестів витрачає ресурси команди. Якщо після кожного рефакторингу коду треба переписувати тести — їхня користь вже під питанням. Цей концепт має назву Tests Fragility і з мого досвіду він не є настільки відомим, як хотілося б. Ознайомитися з теорію тестування можна, наприклад, в цій книзі. Орієнтування на тести також впливає на якість коду. Загалом, код, написаний з думкою про тести буде більш гранулярним та з простішим API. Спробувати тестування на практиці нескладно — достатньо інтегрувати тести в вже готовий проект, або почати писати новий з фокусом на написання тестів.
Алгоритми та структури даних
Знання алгоритмів в сучасному програмуванні це не обов'язкова кваліфікація. В багатьох компаніях прийнято на співбесідах ставити завдання по алгоритмам, хоча в робочому процесі ці навички можуть не знадобитися взагалі. На мою думку, варто приділити час алгоритмам хоча б тому що це досить весело та цікаво. Тим паче сьогодні є можливість вивчати ці теми в інтерактивному форматі, наприклад на LeetCode. Якщо у вас є можливість взяти участь в існуючих контестах з алгоритмічного програмування, наприклад в ACM ICPC, я дуже раджу спробувати. Навіть якщо ці знання не будуть відразу корисними, методи оптимізації коду можуть знайти застосування у будь-якому проекті, а можливість прийняти участь в командному змаганні буде приємним спогадом.
Багатопоточність
З багатопоточністю справа досить цікава. Можна роками писати код не розуміючи навіть простих концептів. Будь який iOS розробник знає, що якщо заблокувати main thread - додаток “зависне”. Але якщо щось іде не так — розібратися в плаваючих та "фантомних" багах, пов'язаних з багатопоточністю можуть тільки програмісти, які розуміють багатопоточний код, та можуть уявити повний таймлайн дій. На мою думку розуміння примітивів синхронізації, потоків, та наслідків нехтування цими поняттями може відділяти Middle розробника від Senior програміста. Для того, щоб розібратися в основних поняттях, рекомендую безкоштовну книгу Little Book of Semaphores. Щоб отримати практичний досвід можна спробувати написати програму, яка робить багато роботи на фоні, та синхронізує результати з UI. Особливо, якщо фонові розрахунки самі по собі потребують деяких потоків. Симулятори деяких фізичних процесів можуть бути гарною початковою точкою.
Графічне програмування
Графічні процесори — частина комп'ютерів, з якою простому розробнику зазвичай не потрібно зустрічатися. Для більшості додатків малювання інтерфейсу або відбувається на рівні CPU, або абстраговано від реального GPU девайсу настільки, що навіть не потрібно про це думати. Але як тільки кількість об'єктів на екрані стає достатньо великою, а зручні абстракції не дають потрібного бусту кадрів в секунду, потрібно опускатися на рівень нижче. Розуміння проблем, які вирішують графічні процесори, а також вміння "пояснити" їм, що треба намалювати допоможе швидко знаходити рішення в схожих ситуаціях. Класичним проектом для вивчення графічного програмування є ігровий рушій. Якщо ви полюбляєте комп'ютерні ігри, як і я, то скоріше за все замислювалися, як розробники ігор програмують їх. В інтернеті є безліч ресурсів по Metal, DirectX, OpenGL або Vulkan. Тільки не розраховуйте, що ваш проект стане новим Unreal Engine. Але якщо ви зможете довести проект до такого стану, в якому у вас буде невелика гра, написана за допомогою вашого рушія, я гарантую безліч цікавих челленджей та отриманих знань на цьому шляху
Вбудоване програмування
Коли я вперше дізнався, що кожний невеликий шматок техніки навколо нас теж має свої програми та процесори, мені відразу стало цікаво спробувати створити щось схоже. Розробка під невеликі мікропроцесори має дуже багато лімітувань. Зазвичай в таких системах обсяг пам'яті не перевищує 128 кілобайт, а про динамічне блокування пам'яті можна забути. Написання та відладка такого коду представляє багато викликів програмісту. Але, як результат, роботу своєї програми можна побачити в "реальному" світі. Навіть блимаючий світлодіод був для мене відкриттям. Також, розуміння роботи мікроконтролерів є першим кроком до розуміння роботи сучасних CPU та операційних систем. При роботі з embedded девайсами може навіть знадобитися знання асемблеру конкретної платформи (зазвичай ARM). Сьогодні почати працювати з мікропроцесорами можна з бюджетних лінійок STM32, також є безліч варіантів готових плат з програматором, які відразу під'єднуються до комп'ютера через USB. Проектів також існує безліч - від динамічного освітлення кімнати до IoT хабу "розумного" дому.
Дізасемблер
Іноді вміння дивитися на код на рівень нижче може бути незамінним. В розробці під платформи Apple, наприклад, ми працюємо з здебільшого closed-source бібліотеками від Apple. Якщо система працює не так, як очікує програміст, то зазвичай потрібно відкривати окремий тікет у Feedback Assistant та чекати (іноді роками!) відповіді. Але якщо озброїтися дизассемблером, то досить часто можна зрозуміти, як працює closed-source код "під капотом". Також може бути корисним вміти читати асемблер власної програми, особливо в контексті оптимізації. Тільки прочитавши скомпільований код, можна сказати що насправді робить ваша програма. Особисто я для цієї мети використовую Hopper Disassembler під macOS.
Компілятори
У світі програмування є свої "закриті" клуби. Якщо говорити про людей, продуктами яких користується найбільше інших інженерів — можна прийти до тих, хто написав компілятор вашої улюбленої мови програмування. До тих пір, доки я не витратив час на вивчення компіляторів, для мене ці програми були нічим іншим, ніж магією. Але, навіть зрозумівши основи, магічний туман все ще не дає збагнути повної величності досягнень авторів цілих мов програмування. Гарні новини є в тому, що існує безліч ресурсів та книг на цю тему. Одна з моїх улюблених — Engineering a Compiler, а також, звісно, Dragon Book. Пірнути в розробку своєї мови програмування можна почавши з Kaleidoscope tutorial від LLVM. У "реальному" житті, якщо ви звісно не інженер компіляторів, такі знання можуть допомогти розуміти усі помилки та поведінки улюбленої мови програмування. Також, більшість компіляторів є open source проектами, що дозволяє зробити внесок в такі величезні проекти. Наприклад, внесок до Swift репозиторія цінується у портфоліо кандидатів у будь-якій компанії.
Основи операційних систем
Якщо є проекти, більші ніж компілятори, то мені на розум приходять тільки операційні системи. Працюючи з комп'ютером більшість свого робочого часу, дуже легко пропустити, що ОС є такою ж програмою, як і ті програми, що ми пишемо. Величезний пласт абстракцій від "заліза" створює ілюзію того, що кожна user space програма має свій незалежний процесор та обсяг пам'яті. Ці абстракції настільки влучні, що написаний та скомпільований одного разу код буде виконуватися на величезній кількості комбінацій процесорів, пам'яті та інших пристроїв комп'ютера. Зробити перші кроки в розумінні ОС допоможе книга Operating Systems: Three Easy Pieces. А для тих, хто хоче ближче познайомитися саме з iOS та macOS, можу порекомендувати безкоштовну MacOS X and iOS Internals. Розуміння внутрішніх процесів ОС закриває останній шматочок пазлу між "залізом" та кодом, який виконує користувач комп'ютера. Для програміста це означає майже повний контроль та розуміння того, що відбувається під час роботи його програми.
Висновки
Оглядаючи свій досвід програмування з наймолодших років, я зрозумів, що маю більш широкі та обьʼємні знання по різних темах на відміну від вузьких спеціалістів. Те, що для мене завжді було справою натхнення та цікавості, перетворилося з хобі у професійну кар’єру. Чи не пізно починати, якщо за спиною вже роки досвіду та комфортна позиція Middle рівня? Я впевнений, що ні. Звісно, розвиток таким чином потребує іноді поступитися власним часом та енергією, працювати навіть вдома та по вихідних. Але з досвідом я можу сказати, що саме глибинні знання у різних темах відділяють просто непоганих програмістів від майстрів своєї справи. Я ніколи не перестану вчитися, тому що для мене цей ідеал недосяжний. Але з кожним роком я знаю більше інформації, в мене є більше проектів, і я ще на один крок ближче до мети.
The Readdle Team