<?xml version="1.0" encoding="utf-8" ?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:tt="http://teletype.in/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"><title>@easy_dev991</title><subtitle>Делюсь интересными находками/лайфхаками в процессе разработки под iOS, и возможно ты найдешь что-то полезное для себя!</subtitle><author><name>@easy_dev991</name></author><id>https://teletype.in/atom/easy_dev991</id><link rel="self" type="application/atom+xml" href="https://teletype.in/atom/easy_dev991?offset=0"></link><link rel="alternate" type="text/html" href="https://teletype.in/@easy_dev991?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=easy_dev991"></link><link rel="next" type="application/rss+xml" href="https://teletype.in/atom/easy_dev991?offset=10"></link><link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></link><updated>2026-07-23T08:27:36.291Z</updated><entry><id>easy_dev991:nQFonqU59Zp</id><link rel="alternate" type="text/html" href="https://teletype.in/@easy_dev991/nQFonqU59Zp?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=easy_dev991"></link><title>Переход с iOS на Android</title><published>2026-07-21T18:19:17.450Z</published><updated>2026-07-21T18:19:30.754Z</updated><category term="android" label="Android"></category><summary type="html">Месяц назад я сменил основной смартфон на андроид, и сейчас расскажу почему и как все прошло.</summary><content type="html">
  &lt;p id=&quot;QEFI&quot;&gt;Месяц назад я сменил основной смартфон на андроид, и сейчас расскажу почему и как все прошло.&lt;/p&gt;
  &lt;h2 id=&quot;sZcb&quot;&gt;Без паники!&lt;/h2&gt;
  &lt;p id=&quot;MNFw&quot;&gt;Для начала успокою своих самых преданных подписчиков: айфон у меня все еще есть - использую его для рабочих задач:&lt;/p&gt;
  &lt;ul id=&quot;Z2Qp&quot;&gt;
    &lt;li id=&quot;Q2sg&quot;&gt;проверить фичу на сборке из testflight (ручное тестирование)&lt;/li&gt;
    &lt;li id=&quot;WTKh&quot;&gt;задебажить хитрый сценарий, который возникает на девайсе, но не на симуляторе (по проводу в Xcode)&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h2 id=&quot;zK98&quot;&gt;Причины для перехода&lt;/h2&gt;
  &lt;h3 id=&quot;AFn7&quot;&gt;Процесс публикации своих приложений&lt;/h3&gt;
  &lt;p id=&quot;FbOP&quot;&gt;Я хотел делать приложения, которыми будет приятно пользоваться, и делиться ими с другими людьми, но недавно закрыли последнюю официальную &amp;quot;лавочку&amp;quot; для оплаты подписки разработчика apple, а без этого невозможно опубликовать приложения для iOS во всеми любимом AppStore.&lt;/p&gt;
  &lt;p id=&quot;5hs0&quot;&gt;Теперь нельзя оплатить аккаунт со счета оператора связи, а искать новые обходные пути (менять регион аккаунта и т.д.) мне не хочется - я ведь не огромная компания с кучей платных подписчиков или постоянным притоком денег.&lt;/p&gt;
  &lt;p id=&quot;xQ6d&quot;&gt;Мне нравилось пользоваться своими приложениями на айфоне - это правда, но мне совершенно не нравилось публиковать свои приложения в аппсторе, потому что это та еще цирковая передача.&lt;/p&gt;
  &lt;p id=&quot;OTnT&quot;&gt;Тем, кто не публиковал приложения сам, или кто публиковал только несколько сборок, наверное сложно будет представить как это происходит.&lt;/p&gt;
  &lt;p id=&quot;a8dE&quot;&gt;&lt;strong&gt;Вкратце процесс выглядит так&lt;/strong&gt;:&lt;/p&gt;
  &lt;ul id=&quot;AaFd&quot;&gt;
    &lt;li id=&quot;BaQ8&quot;&gt;регистрируешься в качестве разработчика apple&lt;/li&gt;
    &lt;li id=&quot;gi8R&quot;&gt;(делаешь само приложение, что обычно не очень сложно и довольно интересно)&lt;/li&gt;
    &lt;li id=&quot;4PRU&quot;&gt;находишь способ оплатить подписку (8990 р/год) - да, не у всех и не с первого раза получалось ее оплатить, и если вы физ.лицо, то никаких встроенных покупок у вас в приложении не будет&lt;/li&gt;
    &lt;li id=&quot;1exN&quot;&gt;заполняешь тонну полей в анкете для создания каждого приложения&lt;/li&gt;
    &lt;li id=&quot;42YQ&quot;&gt;загружаешь приложение в кабинет разработчика&lt;/li&gt;
    &lt;li id=&quot;ORM0&quot;&gt;отправляешь на модерацию&lt;/li&gt;
    &lt;li id=&quot;vwrt&quot;&gt;надеешься, что попадется не стремный модератор&lt;/li&gt;
    &lt;li id=&quot;SBms&quot;&gt;попадается стремный модератор с идиотскими вопросами, ответы на которые есть буквально в той же самой анкете, которую ты уже заполнял ранее&lt;/li&gt;
    &lt;li id=&quot;e6v4&quot;&gt;отвечаешь на все вопросы и ждешь, пока модератор соизволит одобрить приложение или задаст еще какие-нибудь идиотские вопросы&lt;/li&gt;
    &lt;li id=&quot;AKgm&quot;&gt;в случае успешной проверки приложение через некоторое время появляется в магазине ... или не появляется несколько часов без объяснения причин, или через пару дней появится, ну как повезет&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;bHbJ&quot;&gt;И в целом даже с таким стремным процессом (оформление приложения в кабинете apple, модерация) я готов был мириться, пока схема работала хотя бы в таком виде.&lt;/p&gt;
  &lt;h3 id=&quot;0P3k&quot;&gt;Санкции&lt;/h3&gt;
  &lt;p id=&quot;kKYQ&quot;&gt;Бац - удалили банковские приложения. Бац - удалили еще пачку приложений.&lt;/p&gt;
  &lt;p id=&quot;uqj8&quot;&gt;Просто потому что политика, отлично.&lt;/p&gt;
  &lt;p id=&quot;UzJH&quot;&gt;Я конечно поразвлекался, пока загружал приложения от крупных компаний через их обходные пути, в том числе приложение &lt;strong&gt;РЖД&lt;/strong&gt;, которое они распространяют через &lt;strong&gt;Testflight&lt;/strong&gt; для обычных пользователей (ни в какие ворота, ну камон), но надоело.&lt;/p&gt;
  &lt;p id=&quot;r0UU&quot;&gt;Еще просидел около 40 минут в зеленом банке, пока сотрудник банка с тупым взглядом пытался установить мне приложение, и нифига не получилось. &lt;/p&gt;
  &lt;p id=&quot;q5qQ&quot;&gt;Справедливости ради, за неделю до перехода на андроид мне все же удалось в другом офисе этого банка установить приложение, считаю это невероятным везением.&lt;/p&gt;
  &lt;h3 id=&quot;b2Ud&quot;&gt;Операционная система&lt;/h3&gt;
  &lt;p id=&quot;RTsu&quot;&gt;iOS уже не тот. Даже если эта фраза выглядит избитой, то сейчас я для себя это ощутил сполна, когда перешел на iOS 26.&lt;/p&gt;
  &lt;p id=&quot;xhBO&quot;&gt;Да, стекло не каждому нравится, ну и фиг с ним, но зависания на домашнем экране, глюки анимации и прочие проблемы, которые раньше у меня ассоциировались с дешевыми смартфонами на андроиде - это неприемлемо.&lt;/p&gt;
  &lt;p id=&quot;MZDk&quot;&gt;Мои требования к айфону стали слишком высокими, потому что я отлично помню iPhone 5s, который классно работал, и не лагал как iPhone 13 Pro.&lt;/p&gt;
  &lt;p id=&quot;JL4y&quot;&gt;Причем ошибки и тормоза каждый год добавляются поверх старых, как будто так и должно быть, как будто пользователи (в том числе я) должны просто это терпеть - ну нафиг. Забегая вперед - если так и дальше продлится, и если даже андроидом будет невозможно пользоваться, куплю кнопочный телефон. Скриньте.&lt;/p&gt;
  &lt;p id=&quot;qz5q&quot;&gt;Представьте себе, перенести данные с айфона на айфон мне удалось не с первого раза, когда недавно менял айфон.&lt;/p&gt;
  &lt;p id=&quot;mve1&quot;&gt;Руки кривые? Да, но не у меня, а у тех умников, которые пропустили iOS 26 в продакшен и забили на ручное тестирование (по всей видимости, уже очень давно).&lt;/p&gt;
  &lt;h2 id=&quot;r9vk&quot;&gt;Месяц на андроиде&lt;/h2&gt;
  &lt;p id=&quot;32ME&quot;&gt;Процесс переноса данных с айфона на андроид оказался ничем не хуже, чем перенос данных со старого айфона на новый - удалось все перенести со второй попытки (для такой же процедуры с двумя айфонами на iOS 26 пришлось потратить 3 попытки).&lt;/p&gt;
  &lt;h3 id=&quot;gm7H&quot;&gt;Что не понравилось&lt;/h3&gt;
  &lt;p id=&quot;ViJo&quot;&gt;&lt;strong&gt;Сканер отпечатка пальцев&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;Vyqy&quot;&gt;В моем смартфоне ультразвуковой сканер пальца, и это полный отстой по сравнению с face id в айфоне (а ведь еще бывают и оптические сканеры пальца, жуть). Нужно попасть в конкретную зону экрана пальцем, при этом регулярно палец не распознается даже с трех раз. В этом плане пока что андроиды сильно проигрывают айфонам (хотя есть новости о предстоящем добавлении аналога face id, но это где-то в будущем).&lt;/p&gt;
  &lt;p id=&quot;WMYD&quot;&gt;&lt;strong&gt;Системные приложения и баги&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;9r2Y&quot;&gt;Скорее всего привычка к iOS все еще сказывается - просто не хватает некоторых мелочей, которые были удобны в iOS.&lt;/p&gt;
  &lt;p id=&quot;XYIg&quot;&gt;Например, галерея не индексирует фотографии без особых настроек девайса. Через 2 недели после покупки я загуглил как это поправить и за 2 ночи все фото/видео проиндексировались, но некоторые отметили людей с ошибками, а исправить эти ошибки буквально нельзя в стандартном приложении галереи (гугл фото не использую).&lt;/p&gt;
  &lt;p id=&quot;7ERF&quot;&gt;Темная тема не включается/выключается по расписанию при смене режима на &amp;quot;сон&amp;quot; и обратно, что является частой проблемой в купленном мной андроиде, и прочие мелкие проблемы.&lt;/p&gt;
  &lt;h3 id=&quot;PcIR&quot;&gt;Что понравилось&lt;/h3&gt;
  &lt;p id=&quot;jnhG&quot;&gt;&lt;strong&gt;Публикация своих приложений&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;uJyG&quot;&gt;Помните ту дикую инструкцию в самом начале статьи для публикации в аппсторе на iOS?&lt;/p&gt;
  &lt;p id=&quot;n9k7&quot;&gt;Тут шагов всего 2: &lt;/p&gt;
  &lt;ul id=&quot;Q9oK&quot;&gt;
    &lt;li id=&quot;qVmi&quot;&gt;сделать приложение (спасибо агентам за удобство и скорость в этом деле)&lt;/li&gt;
    &lt;li id=&quot;aFse&quot;&gt;установить себе на девайс (и при желании поделиться со всем интернетом)&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;jyj3&quot;&gt;Шок-контент!&lt;/p&gt;
  &lt;p id=&quot;Yb8U&quot;&gt;Я и раньше знал об этом, но пока лично не попробовал, не думал, что это настолько удобно.&lt;/p&gt;
  &lt;p id=&quot;slFr&quot;&gt;Да, система не дает устанавливать приложения не из магазина по умолчанию, но это можно обойти за пару секунд, с помощью системных настроек в разделе &amp;quot;Безопасность&amp;quot;.&lt;/p&gt;
  &lt;p id=&quot;E4XM&quot;&gt;Еще удобно публиковать свои приложения в rustore, хотя сам я его не скачал, но мои приложения там есть, и одно из них регулярно скачивают.&lt;/p&gt;
  &lt;p id=&quot;gg46&quot;&gt;&lt;strong&gt;Сторонние магазины приложений&lt;/strong&gt;&lt;/p&gt;
  &lt;p id=&quot;wyIv&quot;&gt;Я использую f-droid и repostore, и мне очень нравится! &lt;/p&gt;
  &lt;p id=&quot;c5tH&quot;&gt;Например, стандартный ютуб мне не нравится ни в iOS, ни в Android, поэтому я установил другое приложение из гитхаба через repostore, которое мне нравится намного больше, чем официальное от гугла.&lt;/p&gt;
  &lt;p id=&quot;aWgV&quot;&gt;Да, я знаю про риски, и да, я несу ответственность за установку таких приложений сам. Но как будто в гугл-магазине и аппсторе никогда не было мошеннических приложений?&lt;/p&gt;
  &lt;h3 id=&quot;SJX3&quot;&gt;Автоматизация&lt;/h3&gt;
  &lt;p id=&quot;S6tD&quot;&gt;У меня в айфоне были 2 &amp;quot;быстрые команды&amp;quot;, которые активировались либо голосом (как и любая быстрая команда) через Siri, либо нажатием на ярлык на рабочем столе:&lt;/p&gt;
  &lt;ul id=&quot;VMaP&quot;&gt;
    &lt;li id=&quot;RhcZ&quot;&gt;выхожу из дома (для включения блютус + lte, и выключения wifi)&lt;/li&gt;
    &lt;li id=&quot;XM5m&quot;&gt;вернулся домой (обратный процесс)&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;AKMR&quot;&gt;В андроиде эти две команды включаются автоматически без необходимости нажимать на ярлык или выполнять голосовую команду, и это БЕЗ использования геолокации, чудеса!&lt;/p&gt;
  &lt;p id=&quot;UTWs&quot;&gt;Самое классное то, что настроить это можно было без хитровыпендренных завихрений приложения &amp;quot;Команды&amp;quot; (iOS), в котором черт ногу сломит (ну серьезно, никогда не любил процесс создания команд, но полезные команды там все же можно сделать) - просто в системных настройках есть раздел &amp;quot;Режимы и сценарии&amp;quot;, где можно добавлять любые сценарии и делать это с намного более удобным UX.&lt;/p&gt;
  &lt;h2 id=&quot;sOfg&quot;&gt;А что с карьерой?&lt;/h2&gt;
  &lt;p id=&quot;DLfw&quot;&gt;Делать приложения для себя - одно, а работать iOS-разработчиком - совсем другое дело. Я все еще считаю, что было отличным (и удачным) решением научиться этому делу и зайти в эту профессию до активного развития нейросетей.&lt;/p&gt;
  &lt;h2 id=&quot;coBG&quot;&gt;Заключение&lt;/h2&gt;
  &lt;p id=&quot;SeZc&quot;&gt;Да, я знаю про предстоящие изменения в политике гугла и надвигающихся осложнениях в установке приложений не из магазина гугла, но что поделать - будем адаптироваться. В любом случае есть еще PWA, так что не пропадем 😅&lt;/p&gt;
  &lt;p id=&quot;90nC&quot;&gt;Если статья соберет больше 5 лайков, расскажу про критерии, по которым я выбирал себе смартфон на андроиде, и что в итоге выбрал ✅&lt;/p&gt;

</content></entry><entry><id>easy_dev991:G6cggxnKUec</id><link rel="alternate" type="text/html" href="https://teletype.in/@easy_dev991/G6cggxnKUec?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=easy_dev991"></link><title>Краткий обзор ponytail</title><published>2026-07-12T13:00:08.746Z</published><updated>2026-07-12T13:00:29.454Z</updated><category term="agent" label="agent"></category><summary type="html">&lt;img src=&quot;https://img1.teletype.in/files/47/38/47386765-bc56-4397-b3fc-07fcb32800bf.png&quot;&gt;Уже больше недели использую ponytail на постоянной основе в opencode, и мне нравятся результаты.</summary><content type="html">
  &lt;p id=&quot;crRe&quot;&gt;Уже больше недели использую &lt;a href=&quot;https://github.com/DietrichGebert/ponytail&quot; target=&quot;_blank&quot;&gt;ponytail&lt;/a&gt; на постоянной основе в &lt;code&gt;opencode&lt;/code&gt;, и мне нравятся результаты.&lt;/p&gt;
  &lt;h2 id=&quot;NNa6&quot;&gt;Как это работает&lt;/h2&gt;
  &lt;p id=&quot;RvDQ&quot;&gt;Предлагаю прочитать &lt;a href=&quot;https://github.com/DietrichGebert/ponytail/blob/main/README.md&quot; target=&quot;_blank&quot;&gt;ридми&lt;/a&gt; - там есть достаточное количество примеров и описание этого инструмента, а сюда просто скопирую оттуда кусочек:&lt;/p&gt;
  &lt;figure id=&quot;cX1T&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/47/38/47386765-bc56-4397-b3fc-07fcb32800bf.png&quot; width=&quot;962&quot; /&gt;
    &lt;figcaption&gt;Перед тем как написать код, агент проводит такой анализ (скриншот из ридми)&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;mCFQ&quot;&gt;Как я это использую&lt;/h2&gt;
  &lt;h3 id=&quot;gQ7F&quot;&gt;Сценарий 1&lt;/h3&gt;
  &lt;p id=&quot;QDyM&quot;&gt;В пет-проектах, над которыми давно не работал, использую основную команду &lt;code&gt;/ponytail-audit&lt;/code&gt; - эта команда проверяет весь репозиторий, например, проверим &lt;a href=&quot;https://github.com/easydev991/SwiftUI-Days&quot; target=&quot;_blank&quot;&gt;SwiftUI-Days&lt;/a&gt;:&lt;/p&gt;
  &lt;pre id=&quot;MV4N&quot;&gt;Now I have a complete picture of the entire codebase. Here&amp;#x27;s the audit:
yagni ItemSchema.swift + ItemMigrationPlan.swift (157 lines). Three versioned schemas duplicating the model + two custom migration stages that only set optional fields to nil. SwiftData lightweight migration handles this automatically when you just add optional properties. SwiftUI-Days/Models/ItemSchema.swift, SwiftUI-Days/Models/ItemMigrationPlan.swift
shrink BackupFileDocument.swift (217 lines). RawBackupItem duplicates BackupItem with different encode/decode strategy — same 5 fields, two Codable impls. BackupWrapper envelope format + legacy flat array = two parsing paths for one export format. Merge into a single type, drop the legacy path. SwiftUI-Days/Models/BackupFileDocument.swift
yagni Analytics — 4 files (AnalyticsProvider protocol + FirebaseAnalyticsProvider + NoopAnalyticsProvider + AnalyticsService) for one real provider. The protocol has one method and one implementation in production. A single AnalyticsService with a Firebase-only init (or a log closure parameter) replaces 4 files. SwiftUI-Days/Services/Analytics/
yagni SectionTitleView.swift (35 lines). A .bold().foregroundStyle(isEnabled ? .primary : .secondary).frame(maxWidth: .infinity, alignment: .leading) modifier on Text. That&amp;#x27;s a one-line View extension, not a file. SwiftUI-Days/Screens/CommonViews/SectionTitleView.swift
yagni EditSectionView.swift (30 lines). Used in one screen (EditItemScreen). Inline the SectionTitleView + TextField pair. SwiftUI-Days/Screens/Detail/EditSectionView.swift
yagni ReadSectionView.swift (33 lines). Used in one screen (ItemScreen). Inline the SectionTitleView + Text pair. SwiftUI-Days/Screens/Detail/ReadSectionView.swift
yagni DaysEditButton.swift (13 lines). Button { action } Label(.edit, systemImage: &amp;quot;pencil&amp;quot;). Used in two places; inline Button directly is less code than the file overhead. SwiftUI-Days/Screens/Main/DaysEditButton.swift
yagni DaysDeleteButton.swift (19 lines). Same as DaysEditButton. SwiftUI-Days/Screens/Main/DaysDeleteButton.swift
yagni ItemDatePicker.swift (14 lines). A DatePicker with .bold(). Inline. SwiftUI-Days/Screens/Detail/ItemDatePicker.swift
yagni ItemDisplayOptionPicker.swift (24 lines). A Picker with SectionTitleView. Used in two screens; inline both calls. SwiftUI-Days/Screens/Detail/ItemDisplayOptionPicker.swift
yagni ColorTagFilterSheetState.swift (36 lines). Compute-only struct used by one sheet. The three computed properties + two methods can live in the sheet body. SwiftUI-Days/Screens/Main/ColorTagFilterSheetState.swift
yagni Binding+mappedToBool.swift (21 lines). Single-use extension. Inline init(bindingOptional:) at the call site in AppDataScreen. SwiftUI-Days/Extensions/Binding+mappedToBool.swift
yagni ThemeIconScreen+IconViewModel.swift IconError (10 lines). Single-case error enum. Use a descriptive string instead. SwiftUI-Days/Screens/More/ThemeIcon/ThemeIconScreen+IconViewModel.swift
delete BackupFormat.android case. iOS-only app. SwiftUI-Days/Models/BackupFormat.swift
delete AppDataError.swift (5 lines). Single-case enum used once. Use a string literal. SwiftUI-Days/Models/AppDataError.swift
delete ColorTagFilterSheet+Preview.swift (31 lines). 10 static let constants configuring hue/saturation/brightness/count for previews. The previews call static constants that equal literal numbers — use the numbers directly. SwiftUI-Days/Preview Content/ColorTagFilterSheet+Preview.swift
stdlib Color+Hex.swift body (51 lines discounting preview). Hand-rolled hex-to-UInt64 scanner. Scanner already does scanHexInt64. The bit-shifting color extraction is just CGFloat math that UIColor component accessor already provides. Could halve the line count. SwiftUI-Days/Extensions/Color+Hex.swift
shrink DisplayOption.unitsStyle (20 lines). Switch-picking .full/.short/.abbreviated based on which components are nonzero. This is polish: DateComponentsFormatter auto-selects a reasonable style. SwiftUI-Days/Models/DisplayOption.swift
shrink Item.makeDaysCount creates a new DateComponentsFormatter per call. A static let formatter saves the allocation. SwiftUI-Days/Models/Item.swift
shrink FeedbackSender.platformName — nested function inside a computed var body. Extract or inline. SwiftUI-Days/Services/FeedbackSender.swift
yagni ThemeIconScreen+IconVariant.variantNumber — manual switch self returning 1...7. A @frozen enum with Int raw value gives this for free. SwiftUI-Days/Screens/More/ThemeIcon/ThemeIconScreen+IconVariant.swift
net: -~660 lines, -1 dependency (Firebase could go closure-based but kept), -1 file (BackupFormat.android dead path)&lt;/pre&gt;
  &lt;p id=&quot;VcVR&quot;&gt;Дальше закидываю этот анализ в другую модель и прошу составить план безопасного рефактора, чтобы ничего не сломать.&lt;/p&gt;
  &lt;h3 id=&quot;ZAhs&quot;&gt;Сценарий 2&lt;/h3&gt;
  &lt;p id=&quot;4lxk&quot;&gt;В процессе работы проверяю конкретный коммит с помощью команды &lt;code&gt;/ponytail-review&lt;/code&gt;, например:&lt;/p&gt;
  &lt;p id=&quot;oWhI&quot;&gt;&lt;code&gt;/ponytail-review коммит 8e82b6cad16c12c1dcca1574b6908304ef15ccc8&lt;/code&gt;&lt;/p&gt;
  &lt;p id=&quot;UbDx&quot;&gt;В результате получаю похожий отчет, с которым потом можно работать дальше:&lt;/p&gt;
  &lt;pre id=&quot;hJVs&quot;&gt;Ponytail review — коммит 8e82b6ca
Ниже только over-engineering, не correctness.
- ColorTagFilterSheetState.swift:1 yagni Целая структура + enum для двух if-else (applyEnabled/resetEnabled/toggledColorHex/resetResult). Всё в 4 строчки в теле view. Удалить файл.
- MainScreenFilterState.swift:11 shrink itemsCountForFilterButton — синоним visibleItems.count. Убрать, заменить на visibleItems.count в isFilterButtonVisible.
- ColorTagFilterSheet+Preview.swift:9 yagni colors1 = 1, colors3 = 3, colors8 = 8, colors30 = 30 — константы, равные числу. Лишние имена. Вставить числа в вызовы.
- docs/doc-main-screen-color-tag-filter.md:1 yagni 78 строк внутренней документации, которая устареет при следующем рефакторинге. Удалить, пока не появился внешний контрибьютор, которому она нужна.
Net removable: ~40 строк&lt;/pre&gt;
  &lt;h2 id=&quot;3n8o&quot;&gt;Что с рабочим проектом&lt;/h2&gt;
  &lt;p id=&quot;IELI&quot;&gt;Если запустить аудит всего рабочего проекта, то агент предлагает поудалять много нужного кода и зависимостей, поэтому не рекомендую запускать аудит большого проекта целиком. Во всяком случае недорогие модели с такой задачей справляются плохо.&lt;/p&gt;
  &lt;p id=&quot;1cqH&quot;&gt;При этом польза ощутима при выполнении конкретных задач, когда срабатывает проверка на YAGNI из раздела &amp;quot;Как это работает&amp;quot;, и получается меньше кода, чем могло бы быть без этих проверок.&lt;/p&gt;
  &lt;h2 id=&quot;kyri&quot;&gt;Заключение&lt;/h2&gt;
  &lt;p id=&quot;wP8J&quot;&gt;Это уже &lt;strong&gt;пятый&lt;/strong&gt; инструмент для агентов, который я использую на постоянной основе внутри &lt;code&gt;opencode&lt;/code&gt;, а полный список вот: &lt;code&gt;serena&lt;/code&gt;, &lt;code&gt;codegraph&lt;/code&gt;, &lt;code&gt;rtk&lt;/code&gt;, &lt;code&gt;openspec&lt;/code&gt;, &lt;code&gt;ponytail&lt;/code&gt;, и все складывается очень даже удобно для работы с агентом 👍&lt;/p&gt;

</content></entry><entry><id>easy_dev991:2BqBJC8Wrkh</id><link rel="alternate" type="text/html" href="https://teletype.in/@easy_dev991/2BqBJC8Wrkh?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=easy_dev991"></link><title>Экспорт напоминаний Apple</title><published>2026-07-05T10:10:11.486Z</published><updated>2026-07-05T10:35:13.854Z</updated><summary type="html">&lt;img src=&quot;https://img3.teletype.in/files/a3/8a/a38a06a6-ddf0-489b-97e4-2677937971cf.png&quot;&gt;Недавно перешел с ios на андроид и захотел перенести все напоминания из стандартного приложения &quot;Напоминания&quot; на маке/айфоне, но не нашел простого способа как это сделать, поэтому сделал инструмент для экспорта напоминаний.</summary><content type="html">
  &lt;p id=&quot;8g2t&quot;&gt;Недавно перешел с ios на андроид и захотел перенести все напоминания из стандартного приложения &amp;quot;Напоминания&amp;quot; на маке/айфоне, но не нашел простого способа как это сделать, поэтому сделал &lt;a href=&quot;https://github.com/easydev991/export-reminders-from-mac&quot; target=&quot;_blank&quot;&gt;инструмент для экспорта напоминаний&lt;/a&gt;.&lt;/p&gt;
  &lt;h2 id=&quot;mdZD&quot;&gt;Проблема&lt;/h2&gt;
  &lt;p id=&quot;mP4l&quot;&gt;Есть несколько приложений в аппсторе, которые достают напоминания из стандартного приложения и что-то дальше с ними делают (чаще всего просто копируют их в себя).&lt;/p&gt;
  &lt;p id=&quot;83yD&quot;&gt;Однако эти приложения не позволяют бесплатно экспортировать список напоминаний, чтобы делать потом с ними что-то еще.&lt;/p&gt;
  &lt;p id=&quot;56P2&quot;&gt;Синхронизация между платформами тоже нетривиальная задача, и популярные приложения не дают бесплатно синхронизировать напоминания между платформами.&lt;/p&gt;
  &lt;p id=&quot;nb53&quot;&gt;Я даже поробовал microsoft todo, но мне совсем не понравилось их приложение.&lt;/p&gt;
  &lt;h2 id=&quot;RpRE&quot;&gt;Решение&lt;/h2&gt;
  &lt;p id=&quot;jJPW&quot;&gt;Нашел бесплатное и неплохое приложение для андроид &lt;a href=&quot;https://github.com/tasks/tasks&quot; target=&quot;_blank&quot;&gt;Tasks.org&lt;/a&gt;, и сделал небольшой инструмент на свифте для экспорта из приложения &amp;quot;Напоминания&amp;quot; на макбуке в формат &lt;strong&gt;Tasks.org&lt;/strong&gt;.&lt;/p&gt;
  &lt;p id=&quot;8rdp&quot;&gt;Разработку вел целиком с использованием &lt;code&gt;opencode&lt;/code&gt; + &lt;code&gt;openspec&lt;/code&gt; - рассказывал об этом подходе в &lt;a href=&quot;https://teletype.in/@easy_dev991/TQsjWIzfHde&quot; target=&quot;_blank&quot;&gt;предыдущей статье&lt;/a&gt;.&lt;/p&gt;
  &lt;figure id=&quot;igQ9&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/a3/8a/a38a06a6-ddf0-489b-97e4-2677937971cf.png&quot; width=&quot;1424&quot; /&gt;
    &lt;figcaption&gt;Доступные команды в Makefile на момент первого релиза&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h3 id=&quot;rRmV&quot;&gt;Как пользоваться&lt;/h3&gt;
  &lt;ol id=&quot;MbFh&quot;&gt;
    &lt;li id=&quot;uio8&quot;&gt;Клонировать репозиторий&lt;/li&gt;
    &lt;li id=&quot;kBkn&quot;&gt;Открыть терминал в папке проекта&lt;/li&gt;
    &lt;li id=&quot;g3cQ&quot;&gt;Выполнить команду &lt;code&gt;make export-tasks-org&lt;/code&gt;&lt;/li&gt;
    &lt;li id=&quot;3GTF&quot;&gt;Взять получившийся файл &lt;code&gt;reminders_export_tasks_org.json&lt;/code&gt; из папки с проектом и импортировать в андроид-приложение &lt;strong&gt;Tasks.org&lt;/strong&gt;&lt;/li&gt;
    &lt;li id=&quot;pAsn&quot;&gt;Профит&lt;/li&gt;
  &lt;/ol&gt;
  &lt;h2 id=&quot;DZQN&quot;&gt;Выводы&lt;/h2&gt;
  &lt;p id=&quot;7qM9&quot;&gt;Является ли это решение лучшим? Вряд ли. Единственным? Нет. При этом я сделал его довольно быстро, и было очень легко тестировать прямо на симуляторе в андроид-студии.&lt;/p&gt;
  &lt;p id=&quot;Anpp&quot;&gt;Нужны ли знания языка программирования для создания подобных инструментов? Точно нет.&lt;/p&gt;
  &lt;p id=&quot;0Uxk&quot;&gt;Удобно ли мне пользоваться приложением Tasks.org на андроиде? Вполне ✅&lt;/p&gt;
  &lt;p id=&quot;6peF&quot;&gt;Было ли удобнее в стандартном приложении &amp;quot;Напоминания&amp;quot; от apple? 💯 Да    &lt;/p&gt;

</content></entry><entry><id>easy_dev991:TQsjWIzfHde</id><link rel="alternate" type="text/html" href="https://teletype.in/@easy_dev991/TQsjWIzfHde?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=easy_dev991"></link><title>openspec в работе</title><published>2026-06-27T12:09:21.394Z</published><updated>2026-06-27T12:09:48.063Z</updated><category term="agent" label="agent"></category><summary type="html">&lt;img src=&quot;https://img4.teletype.in/files/f1/5d/f15d7427-e310-4ff3-9992-d20d928d0596.png&quot;&gt;Примерно два месяца назад я узнал про openspec, и решил попробовать. Пет-проекты на тот момент были на паузе, поэтому пробовать начал сразу в рабочем проекте. В этой статье покажу как выглядит рабочий процесс с использованием openspec внутри opencode.</summary><content type="html">
  &lt;p id=&quot;vI0G&quot;&gt;Примерно два месяца назад я узнал про &lt;a href=&quot;https://github.com/Fission-AI/openspec&quot; target=&quot;_blank&quot;&gt;openspec&lt;/a&gt;, и решил попробовать. Пет-проекты на тот момент были на паузе, поэтому пробовать начал сразу в рабочем проекте. В этой статье покажу как выглядит рабочий процесс с использованием &lt;strong&gt;openspec&lt;/strong&gt; внутри &lt;strong&gt;opencode&lt;/strong&gt;.&lt;/p&gt;
  &lt;p id=&quot;7W5G&quot;&gt;Дублировать документацию из гитхаба не буду - ее можно прочитать по ссылке в первом абзаце, а расскажу именно про мой опыт использования &lt;em&gt;openspec&lt;/em&gt;.&lt;/p&gt;
  &lt;h2 id=&quot;ybcG&quot;&gt;Установка в проекте&lt;/h2&gt;
  &lt;p id=&quot;4mQl&quot;&gt;В терминале в папке с проектом выполнил команду &lt;code&gt;openspec init&lt;/code&gt; и отметил нужные инструменты (&lt;em&gt;opencode&lt;/em&gt; и т.д.)&lt;/p&gt;
  &lt;figure id=&quot;rfYQ&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/f1/5d/f15d7427-e310-4ff3-9992-d20d928d0596.png&quot; width=&quot;1028&quot; /&gt;
    &lt;figcaption&gt;Выбрал opencode&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;mjs4&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/36/6c/366c67f5-8518-4fd7-ac25-2da29805269c.png&quot; width=&quot;1026&quot; /&gt;
    &lt;figcaption&gt;После нажатия enter нужно перезагрузить IDE, в моем случае - просто завершить сеанс opencode в терминале и запустить его заново&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;TJmR&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/12/2b/122b0da8-e227-4526-b7d5-b10dde024185.png&quot; width=&quot;996&quot; /&gt;
    &lt;figcaption&gt;Теперь нужно закоммитить добавленные в проект навыки и команды, чтобы ими можно было пользоваться&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;06kT&quot;&gt;Использование в работе&lt;/h2&gt;
  &lt;p id=&quot;cab8&quot;&gt;Запускаем &lt;em&gt;opencode&lt;/em&gt; и начинаем вводить команду &lt;code&gt;/o&lt;/code&gt;&lt;/p&gt;
  &lt;figure id=&quot;7Dkp&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/af/d9/afd95472-f7bc-4d89-a477-aa1adf90dcf0.png&quot; width=&quot;2042&quot; /&gt;
    &lt;figcaption&gt;Первые несколько секунд идет загрузка всех команд, а потом в списке появляются новые команды openspec&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h3 id=&quot;y2NE&quot;&gt;Новая мелкая фича&lt;/h3&gt;
  &lt;p id=&quot;xgTV&quot;&gt;Если есть &lt;strong&gt;полное понимание, что нужно делать&lt;/strong&gt;, то можно сразу использовать &lt;code&gt;/opsx-ff&lt;/code&gt; - я так делал два раза для мелких задач, где все максимально очевидно и обсуждать нечего, например:&lt;/p&gt;
  &lt;pre id=&quot;hkWL&quot;&gt;/opsx-ff task1234-toggle&lt;/pre&gt;
  &lt;p id=&quot;9tC6&quot;&gt;Тут &lt;strong&gt;task1234-toggle&lt;/strong&gt; является кратким названием задачи - это важное название и лучше делать его уникальным, чтобы потом было проще ориентироваться в задачах. Потом для продолжения работы над задачей может потребоваться явно передать в промпте это самое название задачи, чтобы агент знал, над которой задачей вы сейчас работаете.&lt;/p&gt;
  &lt;p id=&quot;Kw3Z&quot;&gt;Отправляем промпт в работу, и получаем ответ типа такого: &lt;/p&gt;
  &lt;blockquote id=&quot;3xDA&quot;&gt;I found existing toggle-related code in the project (reminder settings toggle, filter dialog toggle), but &amp;quot;task-1234-toggle&amp;quot; doesn&amp;#x27;t tell me what you want to build or fix.&lt;br /&gt;What do you want this change to do? For example:&lt;br /&gt;- Add a new toggle for some feature&lt;br /&gt;- Fix a bug with an existing toggle&lt;br /&gt;- Refactor toggle logic&lt;br /&gt;Describe the feature/fix and I&amp;#x27;ll create all the OpenSpec artifacts.&lt;/blockquote&gt;
  &lt;p id=&quot;0UWn&quot;&gt;Дальше отправляю промпт с кратким описанием фичи (ведь она мелкая):&lt;/p&gt;
  &lt;blockquote id=&quot;XKrp&quot;&gt;нужно сделать фичефлаг для настройки возможности включения или отключения экрана с логами для разработчика на экране&lt;/blockquote&gt;
  &lt;p id=&quot;EqEq&quot;&gt;Агент какое-то время думает и создает все необходимые документы (артефакты) по задаче:&lt;/p&gt;
  &lt;figure id=&quot;lrtu&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/28/e7/28e70851-53e2-4d00-bf16-689adb0b306a.png&quot; width=&quot;1474&quot; /&gt;
    &lt;figcaption&gt;Окончание работы по созданию документов к задаче&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;5Pa5&quot;&gt;Теперь нужно проверить получившиеся документы самостоятельно (т.к. там действительно немного текста) и при обнаружении нестыковок/ошибок нужно внести правки в документы (вручную или опять же через агента).&lt;/p&gt;
  &lt;p id=&quot;uMFm&quot;&gt;После проверки/исправления всех документов можно сразу переходить к &lt;code&gt;/opsx-apply&lt;/code&gt; или сохранить прогресс (делаем коммит) и переключиться на что-то еще.&lt;/p&gt;
  &lt;h3 id=&quot;crQZ&quot;&gt;Новая стандартная фича&lt;/h3&gt;
  &lt;p id=&quot;eMVp&quot;&gt;Если хочется больше контроля над процессом создания документации, или еще не до конца известны все требования для задачи, то есть смысл начинать с команды &lt;code&gt;/opsx-new&lt;/code&gt;, например:&lt;/p&gt;
  &lt;pre id=&quot;iJJ6&quot;&gt;/opsx-new task1234-medium-feature&lt;/pre&gt;
  &lt;p id=&quot;U2kO&quot;&gt;Отправляем этот промпт и получаем ответ: &lt;/p&gt;
  &lt;blockquote id=&quot;rZbF&quot;&gt;Here&amp;#x27;s the summary:&lt;br /&gt;Change: task1234-medium-feature&lt;br /&gt;Location: openspec/changes/task1234-medium-feature/&lt;br /&gt;Schema: spec-driven (4 artifacts)&lt;br /&gt;Progress: 0/4 complete&lt;br /&gt;[ ] proposal          ← ready now&lt;br /&gt;[-] design             (blocked by: proposal)&lt;br /&gt;[-] specs              (blocked by: proposal)&lt;br /&gt;[-] tasks               (blocked by: design, specs)&lt;br /&gt;First artifact: proposal.md — establish why this change is needed.&lt;br /&gt;Template:&lt;br /&gt;## Why&lt;br /&gt;&amp;lt;!-- Problem/opportunity, 1-2 sentences --&amp;gt;&lt;/blockquote&gt;
  &lt;blockquote id=&quot;Jk78&quot;&gt;## What Changes&lt;br /&gt;&amp;lt;!-- Bullet list: new capabilities, modifications, removals --&amp;gt;&lt;/blockquote&gt;
  &lt;blockquote id=&quot;jhkE&quot;&gt;## Capabilities&lt;br /&gt;### New Capabilities&lt;br /&gt;- &amp;#x60;&amp;lt;name&amp;gt;&amp;#x60;: &amp;lt;description&amp;gt;&lt;/blockquote&gt;
  &lt;blockquote id=&quot;IzeZ&quot;&gt;### Modified Capabilities&lt;br /&gt;&amp;lt;!-- List only if spec-level behavior changes --&amp;gt;&lt;/blockquote&gt;
  &lt;blockquote id=&quot;nLhC&quot;&gt;## Impact&lt;br /&gt;&amp;lt;!— Affected code, APIs, dependencies --&amp;gt;&lt;br /&gt;Ready to create the first artifact? Run /opsx-continue or describe what this change is about and I&amp;#x27;ll draft it.&lt;/blockquote&gt;
  &lt;p id=&quot;RYdh&quot;&gt;В таком сценарии можно делать все документы по порядку, начиная с &lt;em&gt;proposal&lt;/em&gt;, который является кратким описанием задачи для последующей детализации в других документах, напишем промпт с использованием команды &lt;code&gt;/opsx-continue&lt;/code&gt;:&lt;/p&gt;
  &lt;blockquote id=&quot;5Hrr&quot;&gt;/opsx-continue task1234-medium-feature нужно сделать фичефлаг для настройки возможности включения или отключения экрана с логами для разработчика на экране&lt;/blockquote&gt;
  &lt;p id=&quot;o1So&quot;&gt;Отправляем этот промпт и получаем ответ: &lt;/p&gt;
  &lt;blockquote id=&quot;rvTT&quot;&gt;Created: proposal.md&lt;br /&gt;Schema: spec-driven | Progress: 1/4&lt;br /&gt;[x] proposal       ✓&lt;br /&gt;[ ] design          ← unlocked&lt;br /&gt;[ ] specs           ← unlocked&lt;br /&gt;[-] tasks           (blocked by: design, specs)&lt;br /&gt;What&amp;#x27;s in the proposal:&lt;br /&gt;- Why: Нет способа просмотреть логи внутри приложения, нужна фиче-флаг для скрытия от обычных пользователей&lt;br /&gt;- Capabilities: dev-log-screen (экран логов) + dev-log-feature-flag (флаг управления)&lt;br /&gt;- Impact: AppSettingsDataStore, Screen, MoreScreen, новый DevLogScreen + ViewModel&lt;br /&gt;Ready to create the next artifact? Run /opsx-continue — I&amp;#x27;ll draft either design.md or the spec files next.&lt;/blockquote&gt;
  &lt;p id=&quot;5jqU&quot;&gt;Теперь читаем &lt;em&gt;proposal&lt;/em&gt;, вносим правки при необходимости, и либо продолжаем дальше работу в том же формате с командой &lt;code&gt;/opsx-continue&lt;/code&gt;, либо ставим на паузу и переключаемся на что-то другое - главное сделать коммит, чтобы сохранить прогресс.&lt;/p&gt;
  &lt;p id=&quot;BIad&quot;&gt;В нашем случае для примера я &amp;quot;промотаю&amp;quot; создание документов командой &lt;code&gt;/opsx-ff&lt;/code&gt;, чтобы показать как работает &lt;code&gt;/opsx-apply&lt;/code&gt;:&lt;/p&gt;
  &lt;figure id=&quot;F9tI&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/82/a9/82a96c7a-a47a-4f30-a635-574989f86196.png&quot; width=&quot;956&quot; /&gt;
    &lt;figcaption&gt;Агент начал работу&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;1yVU&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/73/64/7364e7c0-773d-41dd-8cb8-e62bfb4e49bd.png&quot; width=&quot;1658&quot; /&gt;
    &lt;figcaption&gt;После окончания работы агент предлагает добавить фичу в архив как выполненную&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;oEUp&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/26/2b/262b15ba-3959-4f58-ae83-28809846a83c.png&quot; width=&quot;1260&quot; /&gt;
    &lt;figcaption&gt;Результат работы - тоггл &amp;quot;Developer logs&amp;quot;&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;LMey&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/c4/dd/c4ddd3fe-cddd-41ef-bace-31c43027b5ca.png&quot; width=&quot;1260&quot; /&gt;
    &lt;figcaption&gt;Если тоггл включить, появится новая кнопка Dev Log&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;CviC&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/92/4a/924ac31c-de1a-4556-a221-ae31446b59c2.png&quot; width=&quot;1260&quot; /&gt;
    &lt;figcaption&gt;А вот и сам экран логов&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;mHIn&quot;&gt;Представим, что положение тоггла было таким и задумано изначально.&lt;/p&gt;
  &lt;p id=&quot;4Afv&quot;&gt;И вот пришло новое требование (ну ничего себе) - нужно тоггл переместить в нижнюю часть экрана. Правим артефакты либо вручную, либо новым промптом (без использования команд &lt;code&gt;/opsx&lt;/code&gt;) и снова вызываем &lt;code&gt;/opsx-apply&lt;/code&gt; для применения правок в коде:&lt;/p&gt;
  &lt;figure id=&quot;FXjg&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b7/37/b73750e2-8a67-4fb3-bad2-63c57fc55742.png&quot; width=&quot;1260&quot; /&gt;
    &lt;figcaption&gt;Успех! Положение тоггла исправлено&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h3 id=&quot;ZL9p&quot;&gt;Верификация статуса&lt;/h3&gt;
  &lt;p id=&quot;RnoL&quot;&gt;Бывает, что задача откладывается на неопределенный срок, пока ее тестируют, обсуждают и т.д., и все это время код по задаче не пишется, но возможно меняются документы (вручную или нет, не важно).&lt;/p&gt;
  &lt;p id=&quot;ZqfY&quot;&gt;Когда к задаче нужно вернуться, то можно проверить статус с помощью команды &lt;code&gt;/opsx-verify&lt;/code&gt;, это я и сделал в нашем случае, вот итоги проверки:&lt;/p&gt;
  &lt;blockquote id=&quot;AM6H&quot;&gt;No critical issues found. &lt;br /&gt;3 warnings to consider — all minor. The implementation correctly follows all design decisions, covers all requirements and scenarios, and maintains code pattern consistency.&lt;br /&gt;Ready for archive. ✓&lt;/blockquote&gt;
  &lt;p id=&quot;d5Hl&quot;&gt;Там сначала идет отчет по шаблону, и в нем перечислены все детали проверок, в нашем случае их нет смысла смотреть, но в реальной задаче следует прочитать и убедиться, что все корректно.&lt;/p&gt;
  &lt;p id=&quot;4sHl&quot;&gt;Когда задачу &amp;quot;приняли&amp;quot; окончательно, ее нужно архивировать командой &lt;code&gt;/opsx-archive&lt;/code&gt;:&lt;/p&gt;
  &lt;blockquote id=&quot;XZmm&quot;&gt;Archive Complete&lt;br /&gt;Change: task1234-medium-feature&lt;br /&gt;Schema: spec-driven&lt;br /&gt;Archived to: openspec/changes/archive/2026-06-27-task1234-medium-feature/&lt;br /&gt;Specs: Delta specs preserved (new capabilities — no main specs to sync to)&lt;br /&gt;All 4 artifacts complete. All 20 tasks complete.&lt;/blockquote&gt;
  &lt;p id=&quot;10QY&quot;&gt;Вот и все! Работа над задачей завершена, теперь любые доработки нужно делать через отдельные задачи (&lt;code&gt;/opsx-new&lt;/code&gt; или &lt;code&gt;/opsx-ff&lt;/code&gt;).&lt;/p&gt;
  &lt;h2 id=&quot;oMdM&quot;&gt;Мой отзыв&lt;/h2&gt;
  &lt;p id=&quot;j5oY&quot;&gt;Мне нравится использовать &lt;em&gt;openspec&lt;/em&gt;, потому что:&lt;/p&gt;
  &lt;ol id=&quot;td2B&quot;&gt;
    &lt;li id=&quot;q6RM&quot;&gt;Стандартизируется рабочий процесс - сначала документация, потом реализация по четкому плану&lt;/li&gt;
    &lt;li id=&quot;2kwI&quot;&gt;Появляется документация в удобном формате прямо в папке с проектом, а не где-то далеко в отдельной системе&lt;/li&gt;
    &lt;li id=&quot;Dzqq&quot;&gt;Удобно отслеживать работу и возвращаться к задаче после длительного перерыва&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;g4Iy&quot;&gt;Не нравится, что агент часто генерирует документацию на английском. Да что уж там, иногда иероглифы до сих пор вставляет то тут, то там 😅, но даже с учетом этого недостатка штука очень удобная.&lt;/p&gt;
  &lt;h3 id=&quot;gfRB&quot;&gt;Нюансы&lt;/h3&gt;
  &lt;ul id=&quot;Rj3x&quot;&gt;
    &lt;li id=&quot;C9Ld&quot;&gt;Многое зависит от используемой модели и настроек проекта (в том числе &lt;code&gt;AGENTS.md&lt;/code&gt;) - не нужно ожидать классную реализацию плана с нужным стилем/подходом, если агент не знает ничего этого&lt;/li&gt;
    &lt;li id=&quot;TsXh&quot;&gt;Даже если проект настроен правильно, нейросеть может ошибиться в составлении документации (например), и потом сделать работу по неправильному плану, поэтому нужно перепроверять документацию и реализацию (как это делать - другой вопрос, кто-то будет сам читать, а у кого-то будут автоматизированные проверки)&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;F6RT&quot;&gt;Еще раз ссылка на репозиторий &lt;a href=&quot;https://github.com/Fission-AI/openspec&quot; target=&quot;_blank&quot;&gt;openspec&lt;/a&gt;, рекомендую попробовать самостоятельно 😉&lt;/p&gt;

</content></entry><entry><id>easy_dev991:Greg5st017e</id><link rel="alternate" type="text/html" href="https://teletype.in/@easy_dev991/Greg5st017e?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=easy_dev991"></link><title>Краткий обзор RTK</title><published>2026-06-08T16:46:02.849Z</published><updated>2026-06-08T16:48:49.996Z</updated><summary type="html">Недавно нашёл ещё один полезный инструмент для использования в opencode — RTK (Rust Token Killer).</summary><content type="html">
  &lt;p id=&quot;w7ME&quot;&gt;Недавно нашёл ещё один полезный инструмент для использования в &lt;code&gt;opencode&lt;/code&gt; — &lt;a href=&quot;https://github.com/rtk-ai/rtk&quot; target=&quot;_blank&quot;&gt;RTK&lt;/a&gt; (Rust Token Killer). &lt;/p&gt;
  &lt;p id=&quot;0Fj6&quot;&gt;Устанавливается одной командой, встраивается через &lt;code&gt;hook&lt;/code&gt; и автоматом сжимает вывод команд перед тем, как он попадёт в контекст нейросети.&lt;/p&gt;
  &lt;h2 id=&quot;md-heading-1&quot;&gt;Как это работает&lt;/h2&gt;
  &lt;p id=&quot;WxZl&quot;&gt;RTK перехватывает команды и применяет к ним четыре стратегии:&lt;/p&gt;
  &lt;ol id=&quot;s7Ip&quot;&gt;
    &lt;li id=&quot;vnBU&quot;&gt;фильтрацию шума&lt;/li&gt;
    &lt;li id=&quot;yzP2&quot;&gt;группировку похожих элементов&lt;/li&gt;
    &lt;li id=&quot;vIF7&quot;&gt;обрезку лишнего&lt;/li&gt;
    &lt;li id=&quot;OidT&quot;&gt;дедупликацию повторяющихся строк.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;GNyd&quot;&gt;В результате модель получает ровно ту же информацию, но в 3–10 раз меньше токенов.&lt;/p&gt;
  &lt;h2 id=&quot;n0jx&quot;&gt;Примеры&lt;/h2&gt;
  &lt;h3 id=&quot;NRgE&quot;&gt;git status&lt;/h3&gt;
  &lt;p id=&quot;QtR5&quot;&gt;&lt;strong&gt;Без RTK (~67 токенов):&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;RKpk&quot;&gt;On branch main
Your branch is up to date with &amp;#x27;origin/main&amp;#x27;.&lt;/pre&gt;
  &lt;pre id=&quot;F0jd&quot;&gt;Untracked files:
  (use &amp;quot;git add &amp;lt;file&amp;gt;...&amp;quot; to include in what will be committed)
	.serena/
	docs/&lt;/pre&gt;
  &lt;pre id=&quot;nzIL&quot;&gt;nothing added to commit but untracked files present&lt;/pre&gt;
  &lt;p id=&quot;jgZs&quot;&gt;&lt;strong&gt;С RTK (~12 токенов):&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;q1dT&quot;&gt;* main...origin/main
?? .serena/
?? docs/&lt;/pre&gt;
  &lt;p id=&quot;qrOY&quot;&gt;Шесть строк превратились в три — при этом полезная информация не потерялась.&lt;/p&gt;
  &lt;h3 id=&quot;md-heading-3&quot;&gt;git diff&lt;/h3&gt;
  &lt;p id=&quot;ZSau&quot;&gt;&lt;strong&gt;Без RTK (~200 токенов):&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;1jgr&quot;&gt;diff --git a/Shared SwiftUI Content/100_ScenePhaseExample.swift b/Shared SwiftUI Content/100_ScenePhaseExample.swift
index 3a4b5c6d..7e8f9a0b 100644
--- a/Shared SwiftUI Content/100_ScenePhaseExample.swift
+++ b/Shared SwiftUI Content/100_ScenePhaseExample.swift
@@ -10,6 +10,7 @@ struct ScenePhaseExample: View {
     @State private var isActive = false&lt;/pre&gt;
  &lt;pre id=&quot;Mvwc&quot;&gt;     var body: some View {
+        // MARK: - Main Content
         VStack(spacing: 20) {
             Text(isActive ? &amp;quot;Active&amp;quot; : &amp;quot;Inactive&amp;quot;)
                 .font(.largeTitle)
&lt;/pre&gt;
  &lt;p id=&quot;tc4y&quot;&gt;&lt;strong&gt;С RTK (~40 токенов):&lt;/strong&gt;&lt;/p&gt;
  &lt;pre id=&quot;Ycrx&quot;&gt;100_ScenePhaseExample.swift: +1
  + // MARK: - Main Content&lt;/pre&gt;
  &lt;p id=&quot;ojbe&quot;&gt;RTK показывает только имя файла, количество изменённых строк и сами добавленные/удалённые строки — без служебной информации &lt;code&gt;diff&lt;/code&gt; (индексы, заголовки патчей, контекстные строки).&lt;/p&gt;
  &lt;h2 id=&quot;md-heading-4&quot;&gt;Установка и настройка&lt;/h2&gt;
  &lt;p id=&quot;5H4A&quot;&gt;С помощью &lt;code&gt;homebrew&lt;/code&gt;:&lt;/p&gt;
  &lt;pre id=&quot;lXBE&quot;&gt;brew install rtk&lt;/pre&gt;
  &lt;p id=&quot;E2E9&quot;&gt;После установки нужно инициализировать &lt;code&gt;hook&lt;/code&gt; для вашего рабочего инструмента:&lt;/p&gt;
  &lt;pre id=&quot;5JrW&quot;&gt;rtk init -g                     # Claude Code / Copilot (по умолчанию)
rtk init -g --gemini            # Gemini CLI
rtk init -g --codex             # Codex (OpenAI)
rtk init -g --agent cursor      # Cursor
rtk init -g --agent windsurf    # Windsurf
rtk init -g --opencode          # opencode&lt;/pre&gt;
  &lt;p id=&quot;gMNc&quot;&gt;После настройки для &lt;code&gt;opencode&lt;/code&gt; в &lt;code&gt;~/.config/opencode/plugins/&lt;/code&gt; появится файл &lt;code&gt;rtk.ts&lt;/code&gt;, который автоматически будет перехватывать вызовы Bash-инструмента и переписывать команды через RTK.&lt;/p&gt;
  &lt;h2 id=&quot;6309&quot;&gt;Заключение&lt;/h2&gt;
  &lt;p id=&quot;mO1P&quot;&gt;RTK — это один из тех инструментов, которые ставишь один раз и сразу получаешь профит. Буквально за пару минут получаем экономию токенов, которая особенно заметна на длинных сессиях при работе с агентом 👍&lt;/p&gt;

</content></entry><entry><id>easy_dev991:orJ5fF-h3jo</id><link rel="alternate" type="text/html" href="https://teletype.in/@easy_dev991/orJ5fF-h3jo?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=easy_dev991"></link><title>Подключаем нейросеть к Xcode</title><published>2026-06-05T09:13:54.508Z</published><updated>2026-06-05T09:16:02.560Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img1.teletype.in/files/41/b0/41b08270-305a-4266-9621-30807738876d.png"></media:thumbnail><category term="i-os" label="iOS"></category><summary type="html">&lt;img src=&quot;https://img1.teletype.in/files/00/39/003964b1-9383-45db-95d7-d066878e3662.png&quot;&gt;В прошлом году презентовали Xcode 26 с возможностью добавления других провайдеров нейросетей кроме chatgpt/claude, но вот незадача - это не так и просто сделать, если не погуглить дополнительно.</summary><content type="html">
  &lt;figure id=&quot;litW&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/00/39/003964b1-9383-45db-95d7-d066878e3662.png&quot; width=&quot;1644&quot; /&gt;
    &lt;figcaption&gt;Xcode выдает ошибку при попытке подключить kimi&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;8cJO&quot;&gt;В прошлом году презентовали &lt;code&gt;Xcode 26&lt;/code&gt; с возможностью добавления других провайдеров нейросетей кроме &lt;code&gt;chatgpt&lt;/code&gt;/&lt;code&gt;claude&lt;/code&gt;, но вот незадача - это не так и просто сделать, если не погуглить дополнительно.&lt;/p&gt;
  &lt;p id=&quot;zeAm&quot;&gt;Для сравнения вот как выглядит настройка в &lt;code&gt;Android Studio&lt;/code&gt;:&lt;/p&gt;
  &lt;figure id=&quot;xXMO&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/55/92/55928ade-57ee-4450-9b14-900c6ccb68cd.png&quot; width=&quot;2188&quot; /&gt;
    &lt;figcaption&gt;Подключается с первого раза без ошибок, чудеса&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;9JLP&quot;&gt;Если просто ввести в настройках &lt;code&gt;Xcode&lt;/code&gt; те же данные, что в &lt;code&gt;Android Studio&lt;/code&gt;, то ничего не выйдет.&lt;/p&gt;
  &lt;p id=&quot;8Tpz&quot;&gt;Причина проблемы в поле URL: &lt;code&gt;Xcode&lt;/code&gt; автоматически добавляет &lt;code&gt;/v1/models&lt;/code&gt; или &lt;code&gt;/models&lt;/code&gt; к URL провайдера для валидации подключения.&lt;/p&gt;
  &lt;p id=&quot;A0QU&quot;&gt;Поэтому нужно удалить часть URL с версией... чтобы &lt;code&gt;Xcode&lt;/code&gt; сам подставил ее. &lt;/p&gt;
  &lt;p id=&quot;t0Tx&quot;&gt;Гениально, не так ли?&lt;/p&gt;
  &lt;figure id=&quot;3xPJ&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/56/14/56140c5d-9238-46f0-8dac-38a9c5c0f47c.png&quot; width=&quot;1644&quot; /&gt;
    &lt;figcaption&gt;Пример корректной настройки для kimi в Xcode&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;h6Ms&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/c2/6d/c26de0e7-40a0-470f-be71-6a91757bd641.png&quot; width=&quot;1644&quot; /&gt;
    &lt;figcaption&gt;Успешно подключили kimi&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;LJKL&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/d0/eb/d0ebadfc-fd5c-44f4-8601-b76bc07ecd4e.png&quot; width=&quot;1644&quot; /&gt;
    &lt;figcaption&gt;Детальный экран подключенного kimi&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;T3Zs&quot;&gt;И чтобы не было подозрений, что я рекламирую kimi для &lt;code&gt;Xcode&lt;/code&gt;:&lt;/p&gt;
  &lt;figure id=&quot;NdSr&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/ba/2b/ba2b11f6-2724-415a-8023-7c81b2bde693.png&quot; width=&quot;780&quot; /&gt;
    &lt;figcaption&gt;kimi нифига не работает в Xcode&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;4JiK&quot;&gt;Всем удачных подключений!&lt;/p&gt;

</content></entry><entry><id>easy_dev991:P3qUJL1LTfs</id><link rel="alternate" type="text/html" href="https://teletype.in/@easy_dev991/P3qUJL1LTfs?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=easy_dev991"></link><title>Отказ от Icon Composer</title><published>2026-04-19T14:01:16.566Z</published><updated>2026-04-19T14:02:20.280Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img2.teletype.in/files/58/bc/58bc94a6-a0ca-4458-a234-7251c37302f2.png"></media:thumbnail><category term="i-os" label="iOS"></category><summary type="html">Если у вас в приложение несколько альтернативных иконок, и все они сделаны с использованием Icon Composer, эта статья для вас.</summary><content type="html">
  &lt;p id=&quot;YYRP&quot;&gt;Если у вас в приложение несколько альтернативных иконок, и все они сделаны с использованием &lt;code&gt;Icon Composer&lt;/code&gt;, эта статья для вас.&lt;/p&gt;
  &lt;p id=&quot;vTFC&quot;&gt;Или если у вас простая иконка, которая почему-то получает тень или стекло при установке приложения на девайс, эта статья для вас.&lt;/p&gt;
  &lt;h2 id=&quot;HgRL&quot;&gt;Предыстория&lt;/h2&gt;
  &lt;p id=&quot;g4ku&quot;&gt;В &lt;code&gt;Xcode 26.1&lt;/code&gt; добавили баг при создании сборки приложения - ассеты иконок, сделанных в &lt;code&gt;Icon Composer&lt;/code&gt; добавляются в итоговый архив несколько раз, что приводит к заметному увеличению веса приложения. Ссылки на форум: &lt;a href=&quot;https://developer.apple.com/forums/thread/804739&quot; target=&quot;_blank&quot;&gt;первая&lt;/a&gt;, &lt;a href=&quot;https://developer.apple.com/forums/thread/821826&quot; target=&quot;_blank&quot;&gt;вторая&lt;/a&gt;.&lt;/p&gt;
  &lt;p id=&quot;PvjP&quot;&gt;Если иконку создать в композере, то она будет выглядеть как и задумано, вот только в итоговой сборке эта иконка будет весить в несколько раз больше, чем нужно. И если в приложении есть альтернативные иконки, то общий вес легко может вырасти в 2 раза для легкого приложения (например, &lt;a href=&quot;https://github.com/easydev991/SwiftUI-Days&quot; target=&quot;_blank&quot;&gt;этого&lt;/a&gt;).&lt;/p&gt;
  &lt;p id=&quot;nJmG&quot;&gt;Обходное решение есть - не использовать композер, и добавлять иконки в приложение старым способом (через ассеты).&lt;/p&gt;
  &lt;p id=&quot;Ctmr&quot;&gt;Однако для простых иконок это приводит к некрасивому результату:&lt;/p&gt;
  &lt;figure id=&quot;OF4i&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b8/ee/b8ee6a3f-71f4-42ab-a3a8-39d359cc5c86.jpeg&quot; width=&quot;136&quot; /&gt;
    &lt;figcaption&gt;Иконка приложения с дефолтным градиентом&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;blockquote id=&quot;8LLt&quot;&gt;Простой я называю иконку, которая состоит из двух цветов без градиентов или прозрачности.&lt;/blockquote&gt;
  &lt;p id=&quot;EoRK&quot;&gt;Получается, что либо мы снижаем вес приложения и миримся с некрасивой тенью (или стеклом, в зависимости от иконки), либо соглашаемся с повышением веса приложения, и целиком управляем тенями и стеклом (привет, композер)?&lt;/p&gt;
  &lt;p id=&quot;HFqF&quot;&gt;&lt;u&gt;Так не пойдет.&lt;/u&gt;&lt;/p&gt;
  &lt;h2 id=&quot;xSmz&quot;&gt;Решение&lt;/h2&gt;
  &lt;figure id=&quot;vRDD&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/ff/fe/fffe123e-29d3-46c1-baaa-56474e25c881.png&quot; width=&quot;472&quot; /&gt;
    &lt;figcaption&gt;Настройка градиента в фигме - добавляем градиент для иконки, чтобы система не считала картинку такой уж простой для накладывания своих лишних эффектов&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;E9Du&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/c0/cd/c0cd6390-2008-4cf8-bd99-0541f6e61f57.png&quot; width=&quot;1850&quot; /&gt;
    &lt;figcaption&gt;Слева старая иконка без градиентов, справа - новая с градиентом. Глазом разницу почти не видно, зато избавляемся от некрасивой тени на экране девайса&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;1PqV&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/00/7b/007b9eb9-19a1-424a-86bb-be3b37aa06ec.png&quot; width=&quot;154&quot; /&gt;
    &lt;figcaption&gt;Так выглядит новая иконка с незаметным градиентом на экране девайса - без тени и стекла&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;AGCC&quot;&gt;Результат в мегабайтах&lt;/h2&gt;
  &lt;figure id=&quot;PFrQ&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/3b/55/3b55d6bf-f705-4c92-967b-7611f85b0508.png&quot; width=&quot;1408&quot; /&gt;
    &lt;figcaption&gt;Размер приложения с иконками, сделанными в Icon Composer&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;TVbJ&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/f9/72/f972833b-1bed-46c8-8b46-2d40580ca6f2.png&quot; width=&quot;1410&quot; /&gt;
    &lt;figcaption&gt;Размер приложения после обновления основной иконки и альтернативных&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;DLAY&quot;&gt;Вес приложения снизился почти на 4 мегабайта!&lt;/p&gt;
  &lt;p id=&quot;FF7Z&quot;&gt;И при этом новые градиентные иконки весят в 5-7 раз больше, чем простые однотонные. Но простые, как мы уже знаем, система покрывает своим стеклом или тенью, а выглядит это некрасиво.&lt;/p&gt;
  &lt;p id=&quot;nbJQ&quot;&gt;Интересный момент: в темной теме ни стекло, ни дополнительная тень на иконки не накладывается - по крайней мере в &lt;a href=&quot;https://github.com/easydev991/SwiftUI-Days&quot; target=&quot;_blank&quot;&gt;счётчике дней&lt;/a&gt; так.&lt;/p&gt;
  &lt;h2 id=&quot;JHCS&quot;&gt;Заключение&lt;/h2&gt;
  &lt;p id=&quot;ZbjO&quot;&gt;Если у вас в приложении много альтернативных иконок, или вы используете &lt;code&gt;Icon Composer&lt;/code&gt; для создания ваших иконок, то будет здорово вернуться к ассетам и подождать, пока композер починят (а починить его не могут уже больше 5 месяцев).&lt;/p&gt;
  &lt;p id=&quot;QSpa&quot;&gt;Зачем заставлять пользователя скачивать лишние мегабайты мусора вместе с нормальным приложением?&lt;/p&gt;

</content></entry><entry><id>easy_dev991:h91zeBj4yyW</id><link rel="alternate" type="text/html" href="https://teletype.in/@easy_dev991/h91zeBj4yyW?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=easy_dev991"></link><title>Чиним синхронизацию Swift Data</title><published>2026-04-17T19:28:53.706Z</published><updated>2026-04-17T19:29:09.532Z</updated><category term="i-os" label="iOS"></category><summary type="html">В моем iOS-приложении для подсчета дней используется Swift Data и в проекте все настроено для автоматической синхронизации данных между всеми девайсами пользователя в iCloud. Сегодня я починил эту синхронизацию (она давно не работала).</summary><content type="html">
  &lt;p id=&quot;4xrH&quot;&gt;В моем &lt;a href=&quot;https://github.com/easydev991/SwiftUI-Days&quot; target=&quot;_blank&quot;&gt;iOS-приложении для подсчета дней&lt;/a&gt; используется &lt;code&gt;Swift Data&lt;/code&gt; и в проекте все настроено для автоматической синхронизации данных между всеми девайсами пользователя в &lt;code&gt;iCloud&lt;/code&gt;. Сегодня я починил эту синхронизацию (она давно не работала).&lt;/p&gt;
  &lt;h2 id=&quot;1IlA&quot;&gt;Проблемный сценарий&lt;/h2&gt;
  &lt;p id=&quot;TAct&quot;&gt;На одном девайсе создаю запись в приложении, жду, сворачиваю/разворачиваю приложение, проверяю на другом девайсе через минуту - там эта запись не появляется.&lt;/p&gt;
  &lt;h2 id=&quot;cC8P&quot;&gt;Решение&lt;/h2&gt;
  &lt;p id=&quot;M3Vp&quot;&gt;Открываем &lt;a href=&quot;https://icloud.developer.apple.com/&quot; target=&quot;_blank&quot;&gt;https://icloud.developer.apple.com/&lt;/a&gt;&lt;/p&gt;
  &lt;figure id=&quot;rBMx&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/19/e7/19e78701-e72f-48f0-9809-a07c98bf2ece.png&quot; width=&quot;1864&quot; /&gt;
    &lt;figcaption&gt;Жмем CloudKit Database&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;oUtH&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/ae/3a/ae3af325-ccc8-4790-bbd5-aab8c031ea7f.png&quot; width=&quot;848&quot; /&gt;
    &lt;figcaption&gt;Выбираем справа сверху настроенный для приложения контейнер и вариант Production&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;3Vy9&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/af/61/af617173-007e-4dbd-83f7-a7c911f67040.png&quot; width=&quot;908&quot; /&gt;
    &lt;figcaption&gt;Открываем логи&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;MLqd&quot;&gt;Находим запись с ошибкой, например так:&lt;/p&gt;
  &lt;figure id=&quot;U2v2&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/d8/f9/d8f993b1-a68d-485d-b47d-df89835d91dd.png&quot; width=&quot;3168&quot; /&gt;
    &lt;figcaption&gt;Фильтруем по OverallStatus = USER_ERROR и жмем справа синюю кнопку Query&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;DEY9&quot;&gt;Проверяем схему (типы записей) в development и production&lt;/p&gt;
  &lt;figure id=&quot;cPuV&quot; class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/93/5c/935cd717-10d2-4571-ba26-5ccf72210d31.png&quot; width=&quot;446&quot; /&gt;
    &lt;figcaption&gt;Жмем сюда для development и production по очереди, чтобы убедиться в наличии нестыковок&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;x0Vg&quot;&gt;Нестыковки найти очень легко: в моем случае в production-схеме буквально не было нужного типа записи с полями из iOS-приложения.&lt;/p&gt;
  &lt;figure id=&quot;OlPK&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img3.teletype.in/files/e5/78/e57896b4-472b-42a4-bd7f-c6b958543fa2.png&quot; width=&quot;3210&quot; /&gt;
    &lt;figcaption&gt;Вот как у меня было в прод-схеме - только один тип записи &amp;quot;Users&amp;quot;&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Q3Nl&quot;&gt;Если найдены нестыковки, и development-схема содержит более актуальные данные, нужно ... опубликовать эти изменения в прод.&lt;/p&gt;
  &lt;figure id=&quot;Incq&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/06/ce/06cee1f4-1fc5-4c55-8ce9-18c079d8aa12.png&quot; width=&quot;3202&quot; /&gt;
    &lt;figcaption&gt;Вот как у меня было в дев-схеме (есть нужный мне тип записи &amp;quot;CD_Item&amp;quot;), и тут же выделил слева внизу кнопку для публикации изменений&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;C4MW&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/33/4a/334ae115-28fd-4fc0-8f26-d6ef91b1f1a8.png&quot; width=&quot;1292&quot; /&gt;
    &lt;figcaption&gt;Перед деплоем можно посмотреть изменения - тут в общем все поля моей модели данных, которая используется в &amp;quot;Счётчике дней&amp;quot; на iOS&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Qit4&quot;&gt;После нажатия &amp;quot;Deploy&amp;quot; можно подождать пару минут и повторить тест на проблемном сценарии. У меня проблема была решена через 2 минуты после деплоя актуальной схемы в прод.&lt;/p&gt;
  &lt;h2 id=&quot;6EhW&quot;&gt;Заключение&lt;/h2&gt;
  &lt;p id=&quot;l4tE&quot;&gt;Когда я в первый раз настраивал &lt;code&gt;Swift Data&lt;/code&gt;, то вообще не заглядывал в консоль &lt;code&gt;icloud.developer&lt;/code&gt;, не проверял ничего связанного со схемами, и даже статей на эту тему не искал и не читал. Оказалось, настроить синхронизацию с облаком несложно, нужно только знать как это делается 😅&lt;/p&gt;
  &lt;p id=&quot;bws5&quot;&gt;Спасибо интернету! И нейросетям 😉&lt;/p&gt;

</content></entry><entry><id>easy_dev991:hlx_HA24Cgy</id><link rel="alternate" type="text/html" href="https://teletype.in/@easy_dev991/hlx_HA24Cgy?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=easy_dev991"></link><title>Какой макбук выбрать в 2026 году</title><published>2026-03-28T10:19:10.347Z</published><updated>2026-03-28T10:22:52.957Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img4.teletype.in/files/7c/ca/7cca7d4a-d86e-4dce-acee-14c2ddc59bca.png"></media:thumbnail><summary type="html">&lt;img src=&quot;https://img2.teletype.in/files/16/2f/162f3954-4a8e-41c5-9496-7cad859f3172.png&quot;&gt;Предыдущая статья про 2025 год доступна по ссылке - большинство рекомендаций из нее все еще актуальны, кроме цен и версии Xcode, конечно.</summary><content type="html">
  &lt;p id=&quot;GWNq&quot;&gt;Предыдущая статья про 2025 год доступна по &lt;a href=&quot;https://telegra.ph/115-Kakoj-makbuk-vybrat-v-2025-godu-04-16&quot; target=&quot;_blank&quot;&gt;ссылке&lt;/a&gt; - большинство рекомендаций из нее все еще актуальны, кроме цен и версии &lt;code&gt;Xcode&lt;/code&gt;, конечно.&lt;/p&gt;
  &lt;p id=&quot;ZOyD&quot;&gt;За год изменилось немного: появился чип &lt;strong&gt;m5 &lt;/strong&gt;и вышел &lt;strong&gt;Xcode 26...&lt;/strong&gt;&lt;/p&gt;
  &lt;h2 id=&quot;Макбук-для-работы&quot;&gt;Макбук для работы&lt;/h2&gt;
  &lt;p id=&quot;RFz4&quot;&gt;Рекомендации по поводу рабочего макбука двигаем на &lt;strong&gt;1&lt;/strong&gt; цифру вперед, то есть на работе заказываем &lt;strong&gt;MacBook Pro m5 pro &lt;/strong&gt;- как обычно, даже в базовой конфигурации это будет отличный вариант на несколько лет вперед.&lt;/p&gt;
  &lt;p id=&quot;Ulxm&quot;&gt;Если компания не выдает технику, то есть смысл взять то, на что хватает денег из линейки &lt;strong&gt;m3&lt;/strong&gt;-&lt;strong&gt;m5&lt;/strong&gt;. &lt;strong&gt;m1&lt;/strong&gt;-&lt;strong&gt;m2&lt;/strong&gt; не рассматриваем, потому что они уже прилично состарились, а &lt;strong&gt;m2&lt;/strong&gt; и вовсе проиграл в некоторых тестах предшественнику.&lt;/p&gt;
  &lt;h2 id=&quot;Макбук-не-для-работы&quot;&gt;Макбук не для работы&lt;/h2&gt;
  &lt;p id=&quot;tB2h&quot;&gt;В 2020 году я купил себе &lt;strong&gt;MacBook Pro 13&amp;#x27;&amp;#x27; m1 &lt;/strong&gt;за&lt;strong&gt; 150к &lt;/strong&gt;(на официальном сайте с доставкой на дом, чудеса вообще), и он отлично прослужил мне до второй половины 2025 года, когда я его продал за &lt;strong&gt;64к&lt;/strong&gt; - это была отличная продажа и я очень доволен таким успехом, и покупатель будет еще долго доволен, т.к. ему макбук нужен был не для программирования, а для повседневного использования.&lt;/p&gt;
  &lt;p id=&quot;wQLY&quot;&gt;В 2026 не могу рекомендовать макбуки из линейки &lt;strong&gt;m1-m2&lt;/strong&gt;, так что находим выгодные варианты &lt;strong&gt;m3&lt;/strong&gt;-&lt;strong&gt;m5&lt;/strong&gt; (как и для работы) на маркетплейсах и радуемся запасу производительности на ближайшие 3-5 лет.&lt;/p&gt;
  &lt;p id=&quot;rAkm&quot;&gt;Очевидно, &lt;strong&gt;m5&lt;/strong&gt; прослужит лучше в течение 5 лет, чем &lt;strong&gt;m3&lt;/strong&gt;, но для рядового пользователя, полагаю, разницы не будет вообще - не всем же нужно запускать &lt;code&gt;Xcode&lt;/code&gt;/&lt;code&gt;Android Studio&lt;/code&gt; каждый день по несколько раз и ждать выполнение unit/ui-тестов 😁&lt;/p&gt;
  &lt;h2 id=&quot;yaz9&quot;&gt;Macbook Neo&lt;/h2&gt;
  &lt;p id=&quot;Lriu&quot;&gt;Сделал отдельный раздел специально для этой модели, потому что в личку мне уже написали гениальную идею купить этот макбук для ios-разработки.&lt;/p&gt;
  &lt;p id=&quot;nfIW&quot;&gt;Этот раздел статьи не для слабонервных!&lt;/p&gt;
  &lt;p id=&quot;I6kO&quot;&gt;.&lt;/p&gt;
  &lt;p id=&quot;xc0g&quot;&gt;.&lt;/p&gt;
  &lt;p id=&quot;rM6S&quot;&gt;.&lt;/p&gt;
  &lt;p id=&quot;Dc1f&quot;&gt;.&lt;/p&gt;
  &lt;p id=&quot;ljUM&quot;&gt;.&lt;/p&gt;
  &lt;p id=&quot;ILCT&quot;&gt;.&lt;/p&gt;
  &lt;p id=&quot;uSq4&quot;&gt;Я серьезно, если вы фанат Apple или просто ярый поклонник всех макбуков, то лучше не читать дальше!&lt;/p&gt;
  &lt;p id=&quot;VjEX&quot;&gt;.&lt;/p&gt;
  &lt;p id=&quot;G5Hd&quot;&gt;.&lt;/p&gt;
  &lt;p id=&quot;AHif&quot;&gt;.&lt;/p&gt;
  &lt;p id=&quot;I9uX&quot;&gt;.&lt;/p&gt;
  &lt;p id=&quot;Xx1J&quot;&gt;.&lt;/p&gt;
  &lt;p id=&quot;ulIb&quot;&gt;.&lt;/p&gt;
  &lt;p id=&quot;7gTg&quot;&gt;Вы еще тут? Окей, поехали)&lt;/p&gt;
  &lt;p id=&quot;hWNE&quot;&gt;Специально для этой модели я покажу скриншоты цен (актуально на конец марта - начало апреля 2026) без рекламы конкретного маркетплейса, и потом мы вместе сравним с ценами на другие модели на том же маркетплейсе, опять же не реклама:&lt;/p&gt;
  &lt;figure id=&quot;pnBQ&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/16/2f/162f3954-4a8e-41c5-9496-7cad859f3172.png&quot; width=&quot;2268&quot; /&gt;
    &lt;figcaption&gt;Цены на безымянном (популярном) маркетплейсе на Macbook Neo - от 66к руб с учетом пошлины&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;E9Xj&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/b8/32/b832a1ec-d3a0-420d-a268-01144b1c17ea.png&quot; width=&quot;2318&quot; /&gt;
    &lt;figcaption&gt;Цены на том же маркетплейсе на Macbook Air M4 - от 89к руб с учетом пошлины&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;Ajp4&quot;&gt;&lt;strong&gt;Важная деталь&lt;/strong&gt;: это сравнение цен на новые ноутбуки, т.е. не б/у, не паленые, а прямо новые.&lt;/p&gt;
  &lt;p id=&quot;CFKc&quot;&gt;&lt;strong&gt;Air m4&lt;/strong&gt; дороже на &lt;strong&gt;23к&lt;/strong&gt; руб (на этом маркетплейсе), но и по большинству параметров он намного лучше.&lt;/p&gt;
  &lt;p id=&quot;9vhE&quot;&gt;У мелких перекупщиков на других популярных сайтах можно найти тот же &lt;strong&gt;air m4&lt;/strong&gt; за &lt;strong&gt;69к&lt;/strong&gt;.&lt;/p&gt;
  &lt;p id=&quot;hHov&quot;&gt;&lt;u&gt;Внимательный&lt;/u&gt; читатель может спросить: &amp;quot;&lt;em&gt;Зачем покупать дорогой air m4, если можно купить новый модный и молодежный neo дешевле?&lt;/em&gt;&amp;quot;.&lt;/p&gt;
  &lt;p id=&quot;jsVf&quot;&gt;На это я &lt;em&gt;отвечу&lt;/em&gt; внимательному читателю: &amp;quot;&lt;em&gt;Если не получается найти разницу при беглом сравнении параметров обеих моделей под свои потребности, то не нужно платить больше&lt;/em&gt;&amp;quot;.&lt;/p&gt;
  &lt;p id=&quot;n66a&quot;&gt;Потом &lt;u&gt;сообразительный&lt;/u&gt; читатель может спросить: &amp;quot;&lt;em&gt;Зачем вообще покупать макбук в 2026 году за такие деньги не для ios-разработки, когда можно купить ноутбук на виндовс под любые потребности и по любой цене, в том числе от 15к и до 60к?&lt;/em&gt;&amp;quot;&lt;/p&gt;
  &lt;p id=&quot;GInl&quot;&gt;На что я отвечу сообразительному читателю: &amp;quot;&lt;em&gt;Отличный вопрос, мой дорогой читатель! Нет никакого смысла тратить деньги на макбук, если нет конкретных задач, для которых нужен именно макбук, и с которыми не справятся другие ноутбуки&lt;/em&gt;&amp;quot;.&lt;/p&gt;
  &lt;p id=&quot;eLf5&quot;&gt;И пока другие блогеры и СМИ активно пиарят новый &lt;strong&gt;macbook neo&lt;/strong&gt; как убийцу доступных ноутбуков на винде, мы с вами как самые сообразительные понимаем, что это пустой трёп, который нацелен только на отработку рекламного ТЗ, или на сбор хайпа (или и то, и другое разом).&lt;/p&gt;
  &lt;figure id=&quot;fIlM&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/92/09/920960e0-5641-4551-bb55-18da1fbb2857.png&quot; width=&quot;2266&quot; /&gt;
    &lt;figcaption&gt;Вот пример реальных убийц macbook neo на том же маркетплейсе дешевле 25к руб. В карточках товара кринж, но это не так важно.&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;p id=&quot;gY7l&quot;&gt;И прежде чем набегут желающие защитить божественный бренд Apple от сравнения с безымянными ноутбуками, сначала вспомним, что этот раздел был не для слабонервных и не для фанатов Apple!&lt;/p&gt;
  &lt;p id=&quot;srx3&quot;&gt;А теперь можно вместе подумать, что еще можно купить на оставшиеся 45к руб после покупки ноутбука на винде:&lt;/p&gt;
  &lt;ul id=&quot;0rEu&quot;&gt;
    &lt;li id=&quot;xx5Z&quot;&gt;Отличный новый андроид-смартфон&lt;/li&gt;
    &lt;li id=&quot;2qoL&quot;&gt;Два хороших новых андроид-смартфона&lt;/li&gt;
    &lt;li id=&quot;oxUm&quot;&gt;Хороший андроид-смартфон и еще один ноутбук на винде&lt;/li&gt;
    &lt;li id=&quot;nnbN&quot;&gt;Два дополнительных ноутбука на винде&lt;/li&gt;
    &lt;li id=&quot;1ABD&quot;&gt;45 пицц по 1000 рублей каждая&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;z2uI&quot;&gt;Ну вы поняли, надеюсь 😉&lt;/p&gt;
  &lt;h2 id=&quot;oBfa&quot;&gt;Заключение&lt;/h2&gt;
  &lt;p id=&quot;AYFS&quot;&gt;Итоговый выбор как всегда зависит от ваших конкретных задач (но не покупайте, пожалуйста, &lt;strong&gt;macbook neo&lt;/strong&gt;), для которых выбирается макбук, и в большинстве случаев для разработки подойдет любая модель с чипом &lt;strong&gt;m4&lt;/strong&gt;-&lt;strong&gt;m5&lt;/strong&gt;.&lt;/p&gt;
  &lt;p id=&quot;gfix&quot;&gt;Удачных покупок!&lt;/p&gt;

</content></entry><entry><id>easy_dev991:baZfVYrGA5H</id><link rel="alternate" type="text/html" href="https://teletype.in/@easy_dev991/baZfVYrGA5H?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=easy_dev991"></link><title>Загружаем фото в андроид-эмулятор</title><published>2026-03-20T19:18:24.928Z</published><updated>2026-03-20T19:19:44.680Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img2.teletype.in/files/1e/19/1e199205-20aa-4772-9b17-0e91fcd114fa.png"></media:thumbnail><summary type="html">&lt;img src=&quot;https://img2.teletype.in/files/51/55/5155b125-26a8-44dc-8192-92da8d2af2a6.png&quot;&gt;В процессе разработки андроид-приложения бывает нужно протестировать функционал добавления фотографий из галереи в приложение.</summary><content type="html">
  &lt;p id=&quot;DZbY&quot;&gt;В процессе разработки андроид-приложения бывает нужно протестировать функционал добавления фотографий из галереи в приложение.&lt;/p&gt;
  &lt;p id=&quot;uvnt&quot;&gt;Есть разные способы загрузки фоток в эмулятор, например:&lt;/p&gt;
  &lt;ul id=&quot;qJML&quot;&gt;
    &lt;li id=&quot;iMIh&quot;&gt;перетащить файлы с фотками на экран эмулятора&lt;/li&gt;
    &lt;li id=&quot;mVuf&quot;&gt;перетащить файлы с фотками в открытое приложение &amp;quot;файлы&amp;quot; на экране эмулятора&lt;/li&gt;
    &lt;li id=&quot;xIBT&quot;&gt;открыть Device Explorer и добавить фотки в папку sdcard/DCIM&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p id=&quot;LOpN&quot;&gt;Но что бы вы ни сделали, все эти способы могут не привести к желаемому результату...&lt;/p&gt;
  &lt;p id=&quot;SB53&quot;&gt;А вот кстати и желаемый результат:&lt;/p&gt;
  &lt;figure id=&quot;1xXu&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img2.teletype.in/files/51/55/5155b125-26a8-44dc-8192-92da8d2af2a6.png&quot; width=&quot;1080&quot; /&gt;
    &lt;figcaption&gt;В приложении можно открыть галерею фотографий&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure id=&quot;ddko&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/0e/a8/0ea83121-a09d-4551-ad5c-df2c3961292e.png&quot; width=&quot;1080&quot; /&gt;
    &lt;figcaption&gt;Фото из галереи можно выгрузить в приложение&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;KUrD&quot;&gt;Проблема&lt;/h2&gt;
  &lt;p id=&quot;8TnF&quot;&gt;Все перечисленные ранее способы не сработали:&lt;/p&gt;
  &lt;figure id=&quot;pslV&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img1.teletype.in/files/0f/95/0f9536df-c57a-4c4c-bac2-35b650a96af1.png&quot; width=&quot;1080&quot; /&gt;
    &lt;figcaption&gt;Фотографии добавлены в эмулятор каждым из перечисленных ранее способов, но приложение их не видит (как и сам эмулятор)&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;9Tk4&quot;&gt;Решение&lt;/h2&gt;
  &lt;p id=&quot;cRx5&quot;&gt;После копирования фотографий на эмулятор любым из ранее перечисленных способов выключаем эмулятор и жмем &lt;code&gt;Cold Boot&lt;/code&gt;:&lt;/p&gt;
  &lt;figure id=&quot;qK93&quot; class=&quot;m_column&quot;&gt;
    &lt;img src=&quot;https://img4.teletype.in/files/fb/e3/fbe3b5a9-9508-4f3a-bb0e-e78475f5c01c.png&quot; width=&quot;1080&quot; /&gt;
    &lt;figcaption&gt;Чудо-кнопка, решающая проблему с обнаружением фотографий в эмуляторе&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;h2 id=&quot;AMrX&quot;&gt;Заключение&lt;/h2&gt;
  &lt;p id=&quot;lQAa&quot;&gt;Перед написанием этой статьи я пробовал добавить фотографии в эмулятор всеми перечисленными способами, даже стирал данные эмулятора и перезагружал его - ничего не помогало.&lt;/p&gt;
  &lt;p id=&quot;VheN&quot;&gt;И только чудо-кнопка &lt;code&gt;Cold Boot&lt;/code&gt; помогла.&lt;/p&gt;
  &lt;p id=&quot;Ox3a&quot;&gt;Будет здорово, если кому-то эта статья поможет сэкономить время в подобной ситуации &lt;/p&gt;

</content></entry></feed>