(не) классифицируйте (некоторые) свой код
Предупреждение: покупатель, будьте осторожны, никогда не делайте этого, вся ваша кодовая база самоуничтожится, это ужасная идея, вы дерьмовый кодер, если сделаете это, и около 100 других предупреждений, которые все закончить с некоторой вариацией здесь есть драконы. Так что не делайте этого. Или делайте это, потому что иногда «правила» просто мешают вам, или, может быть, нет, потому что вернуться к источнику правды и написать целую каскадную перезагрузку веселее. Что бы ни. Не вините меня, если вы тратите часы или недели, или ваш компьютер сгорает, вас увольняют, ваш супруг бросает вас ради более сексуального кодера, который никогда не экспериментирует, или что-то в этом роде. В любом случае — каждый случай — следуйте на свой страх и риск. Это должно прикрыть мою задницу от огня и купороса со стороны как новичков-«экспертов», так и ветеранов-настоящих экспертов.
Оглядываясь назад на проект, я однажды работал над каким-то SwiftUI garba… э… кодом, просто пытаясь сделать очень простую вещь. Вообще говоря, я люблю Swift (но я бы хотел, чтобы они уже перестали менять так много фундаментальных вещей), и у SwiftUI есть свои преимущества. Я по-прежнему считаю, что UIKit — это хорошо, и когда вы используете его регулярно, он достаточно быстр, чтобы делать вещи, но SwiftUI — это четкий и реальный путь Apple в будущее. Игнорируйте это на свой страх и риск¹.
Во всяком случае, у меня была ситуация, когда… назовем это сущность²…, представляющая пациента, содержит два необязательных списка; один содержит список состояний (диабет, замена сустава, хроническая мигрень и т. д.), которые ввел пациент, а другой представляет собой список представлений о физическом, стоматологическом или эмоциональном состоянии, которые врачи могут просмотреть или рассмотрели в последний [выбранный период времени].
Изначально система просто не отображала ранее проверенные материалы. Руководство хотело, чтобы они по-прежнему появлялись в пределах временных рамок и указывали, были ли они проверены или нет, и чтобы этот показатель изменился после того, как врач пометит его как проверенный.
Пациент — это структура. Условие представляет собой структуру. Представление представляет собой структуру. Сущность отправки содержит ряд полей, включая, помимо прочего, текст, который ввел пациент, и флаг, указывающий, была ли заявка рассмотрена или нет. Один простой, непритязательный, легкий для понимания логический флаг. Был пересмотрен или нет. Период. Очень просто. Наряду с этим существуют и другие данные, но в рамках данного обсуждения этот логический флаг — это все, что имеет значение.
Это может иметь значение, а может и не иметь, но приложение, в котором используются эти данные, является родным приложением для iPad, которое, как я полагаю, также может работать на компьютерах M(x) Mac с использованием исполнительной системы iOS. Как это называется? Это Катализатор? Что бы ни. Кажется, это работает нормально.
При просмотре представленных материалов врач или PA⁴ имеет возможность нажать кнопку, которая отмечает представление как проверенное. В рамках установки этого флага происходят и другие вещи, в том числе уведомления пациентов, но эти вещи выходят за рамки этого разговора и касаются проприетарных знаний и интеллектуальной собственности, так что это настолько глубоко, насколько я хочу.
Система была разработана таким образом, что у врача есть список назначенных пациентов, у каждого пациента есть этот список состояний и представлений, описанных ранее, и есть ряд экранов, которые представляют эту взаимосвязь сущностей и действия, которые врач может предпринять на протяжении всего жизненного цикла. объекта пациента⁵ и связанных с ним членов.
Установка проверенного флага вызывает обратный вызов через вызовы REST к серверу (менее)⁶ API для обновления данных в базе данных и возврата значений пациенту и, возможно, другому медицинскому персоналу в группе ухода за пациентом. Одно маленькое логическое значение. После того, как код установлен и клиентский код получает свой счастливый маленький код ответа 200, локальный код теперь должен представить это врачу, установив флажок… с помощью этого маленького логического значения.
Я точно знаю? Это было увлекательное путешествие. Но правда в том, что было много приготовлений, чтобы просто добраться до начала нашего пути. Итак, поехали.
Теперь, когда мой интерактор API знает об этом, и все вышестоящие все выполнили свою работу и изменили значение, что произойдет дальше? Это преобразование false-›true должно быть отражено в объекте Submission и распространено через пользовательский интерфейс. Одна из «радостей» «декларативных» разработчиков пользовательского интерфейса заключается в том, что неизменяемое состояние является нормой, а пользовательский интерфейс является результатом состояния. Причудливые слова, чтобы сказать: «Я нарисую пользовательский интерфейс, как только узнаю, каковы все мои значения».
По умолчанию… ну… состояние пользовательского интерфейса в приложении SwiftUI является статическим, доступным только для чтения, сгенерированным один раз для отображения, система никогда не обновляется. Мы используем причудливые декораторы, такие как @State и @ObservableObject, для хранения значений, которые по своей природе переменчивы, и изменение этих значений вызывает перерисовку пользовательского интерфейса.
Все это говорит о том, что предпочтительный, более легкий и неизменяемый способ хранения данных — скромная структура — не может быть легко изменен сам по себе, и это может привести к большому количеству обновлений в пользовательском интерфейсе или может быть затруднено. чтобы точно понять, когда и почему происходят некоторые из этих обновлений.
Представьте, что вы хотите, чтобы ваш почтовый ящик был окрашен в красный цвет. Ты можешь просто покрасить свой почтовый ящик в красный цвет. В мире ООП это было бы похоже на ваш код, напрямую вызывающий метод объекта почтового ящика.
// yes, this example is silly and convoluted, but here we go var mailbox = myhouse.getObject( HouseholdObjects.mailbox ) mailbox.setColor(.red)
Whammo, теперь ваш почтовый ящик красный.
В декларативном мире с неизменяемым состоянием процесс больше похож на то, как вы звоните парню, который построил ваш дом, говорите ему, что хотите, чтобы ваш почтовый ящик был окрашен в красный цвет, и вешаете трубку, а затем ждете и занимаетесь другими делами, пока кто-нибудь не придет к вам. подойди, забери почтовый ящик, покрась его в красный цвет, затем переустанови его, и в это время он перезвонит тебе, и ты выйдешь на улицу и просмотришь его.
Ну, на самом деле это было бы больше похоже на то, что строитель усыпил бы всю улицу и восстановил бы все с нуля, включая ваш красный почтовый ящик, и все было бы возвращено так, как должно было быть… ваш теперь уже красный почтовый ящик и все такое. Ваши соседи, вероятно, возненавидели бы вас, но посмотрите, как все свежо и чисто, и вам не пришлось ничего делать.
// stupid formatting to keep you from scrolling because it's difficult let truth = "I'm not writing all the pseudo-code " + "to represent that whole chain of events";
Но наша дилемма такова; мы изменили один небольшой бит данных глубоко в куче данных, которые мы получили ранее из нашего API. Мы получаем все это снова? Мы возьмем только одного пациента? Или мы получаем только одно представление? Поскольку разрешенный объект данных неизменяем, мы не можем просто сказать что-то вроде:
patients[124].submissions[76].reviewed = true
Или… можем?
В Swift неизменяемые структуры обычно выражают свои поля с помощью переменных let (только для чтения один раз), например:
struct Patient: Codable, Identifiable { let id: Int let name: String // let ... and so on }
У программистов есть возможность сделать эти переменные теоретически доступными для записи, изменив let на var, а затем украсив метод модификатором mutating, сказав компилятору, чтобы он успокоился, расслабился и не кричал, когда что-то изменилось. При этом данные этой переменной отправляются в целое путешествие, которое лучше описано в другом месте. Вот ссылка на довольно серьезное обсуждение того, что происходит, как это происходит, а также преимущества и недостатки использования изменяемых функций в структуре («https://chris.eidhof.nl/post/structs-and-mutation-in- быстрый/" ).
Но… правильный ли это путь? Я, вероятно, должен сразу сказать, что нет правильного способа изменить данные в системе, лучше всего предназначенной для неизменяемых данных. Если вы делаете это, вам, вероятно, следует пересмотреть свой дизайн. Но иногда вы что-то модифицируете по просьбе руководства, а они не выделяют времени и бюджета на 11-часовые изменения или пост-продакшн такого типа, и иногда вам приходится плавать в грязи, чтобы сделать что-то. .
Структура не является классом, пока вы не сделаете ее таковой
В качестве забавного эксперимента, и поскольку у меня был идентификатор пациента, отправка и я знал, какие данные нужно изменить, я решил просто изменить все LET на VAR в структуре и изменить структуру на класс, украшенный @ObservableObject, и в подпредставлении подпредставления подпредставления, которое рисует проверенный/непроверенный индикатор и его кнопку, я изменил тип параметра, чтобы взять весь объект Submission, выполнить обратный вызов API через интерактор API @EnvironmentObject и изменить класс сразу после успеха.
Это изменение кода заняло около 30 минут, чтобы просмотреть все различные места и сценарии, в которых использовался класс struct cum, протестировать его с изменением, перезагрузить, перезапустить, перезагрузить около 10 раз с различными другими ситуациями, присутствующими во время тестирования, и все это просто работал. Это сработало… и я имею в виду на удивление хорошо. Я ожидал много нытья от компилятора, но он был странно тихим.
Я отправил версию приложения в TestFlight для тестирования с внутренними врачами, и в конечном итоге она была переведена в производственную версию с рядом других изменений.
Никто не взорвался.
Никто не умер.
Никто не звонил и не жаловался, что что-то не работает или работает как раньше.
Никто даже не заботился, когда я объяснял, потому что, о да, менеджмент != технология, и никого не заботило ничего, кроме результатов.
Ничего плохого не случилось.
Еще.
ОООООООООООООООООООООООООООООООООООООООООООООООООООООООООООООООООООООчень, больше не моя проблема». Это дерьмо выпущено и в дикой природе, сделано и закончено, и я давно перешел к… гм… другим вызовам.
Не делайте этого. Это неправильный путь. Желаю вам всегда иметь бюджет, время, знания и опыт, а также поддержку руководства, чтобы всегда делать каждую мелочь правильным образом… даже когда речь идет всего лишь об одном маленьком логическом значении.
¹ Это не означает, что UIKit скоро умрет. Существуют миллионы и миллионы строк кода, использующих UIKit, и они не исчезают просто волшебным образом. Даже если вы закоренелый ненавистник Swift, приверженец Objective-C и считаете Swift дьявольской заразой, вы все равно сможете найти работу на очень и очень долгое время.
² Чтобы успокоить людей, которые ненавидят ООП³ Я стараюсь избегать использования слова объект, но будьте осторожны; вы, ребята, как правило, разделяетесь на два лагеря, и один из этих лагерей чертовски неверен, потому что вся ваша система убеждений основана на ложном представлении о том, что ООП по своей сути является злом, не создает ничего, кроме спагетти-кода, и не функционально исправен. Я утверждаю, что люди думают, что это просто отстой в техническом дизайне и им нужно потратить некоторое время на изучение основ. Начните с https://en.wikipedia.org/wiki/The_C_Programming_Language Денниса Ритчи.
³ Объектно-ориентированное программирование — https://en.wikipedia.org/wiki/Объектно-ориентированное_программирование
⁴ Помощник врача — https://en.wikipedia.org/wiki/Physician_assistant
⁵ Ха! Там. Я использовал слово объект.
⁶ Можем ли мы прекратить всю эту тупость термином «бессерверный»; количество вещей, которые действительно бессерверны, вероятно, колеблется от подростков или, может быть, сотен в пантеоне всех современных пакетов программного обеспечения, поддерживающих Интернет. Просто потому, что вы на самом деле не владеете им и не поддерживаете его, ваше дерьмо работает где-то на сервере, даже если этот сервер является контейнером, работающим на чьем-то более крупном и мощном сервере. Для вас это только «без сервера», что просто означает, что вы не платите за хостинг на выделенной машине или у вас нет собственного центра обработки данных. Правильным термином будет удаленный сервер или виртуальный сервер. «Бессерверный» — глупый термин.