Суть, которую я хотел донести, состоит в том, что Великолепный Инструмент не обратил внимание на подозрительные части, а безропотно помог лишь ещё сильнее ухудшить и без того стремноватую функцию.
Имхо функция сначала была просто плохой и непонятной, а после этого "патча", она стала совсем плохой и ещё менее понятной для программиста. И проблема не в квалификации читающего. Я изо всех сил пытался удержаться от комментария по поводу "15 лет программирования", но не смог. Мне кажется, за 15 лет такие функции должны начать вызывать неприятные чувства.
Более того, тот "голос", который говорит в моей голове при чтении и осмыслении кода, использует другие "слова", другой порядок, совершенно другой подход. Для меня чтение вот таких объяснений это как слушать лекцию человека с неприятным тебе голосом, или с некомфортным темпом рассказа, или с фокусом совершенно не на то, что тебе интересно.
И в чём польза этого текстового описания для кода? Его всё равно надо осмыслить и загрузить себе в мозг, чтобы потом произвести нужное изменение. Так может проще прочитать код?
Зачем в работающем приложении на горячую обновлять локализацию? Никто не умрёт, если новая локализация применится при следующем перезапуске. Зато сколько жизни можно сэкономить не поддерживая такую маргинальную фичу.
guard let data = try? Data(contentsOf: url),
let infoPlist = String(data: data, encoding: .utf8)
else { fatalError(.infoPlistNotFound) }
Если do { try f() } catch { fatalError() } и f()! это в принципе одно и то же (потому что одинаково напечатается одинаковая ошибка и одинаково упадёт), то здесь же стало хуже. try! Data(...) напечатал бы гораздо больше полезной информации о том, почему же не получилось прочитать данные, чем просто "infoPlistNotFound". Что ещё и не факт, что правда. Файл-то может быть found, но не смочь прочитаться по тысяче причин: недостаточно прав, прочитался только до половины, да чёрт ещё знает почему. Полезная информация, которая могла бы быть в логах, и помочь расследованию, оказывается просто потеряна.
Глядя на код в репозитории, я увидел множество проблем с этим примером. Какие-то касаются кода, какие-то более концептуальные. Я даже и не знаю с чего начать.
Начну пожалуй с любимого:
static func fetchDomainsJson(remotePath: String) -> [Domain] {
guard let url = URL(string: remotePath) else { fatalError(.remotePathIsInvalid) }
do {
let data = try Data(contentsOf: url)
return try JSONDecoder().decode([Domain].self, from: data)
} catch {
fatalError(.failedToLoadRemoteFile(error))
}
}
Обожаю эти do { try f() } catch { fatalError(error) }. Почему бы просто не сделать try! – система точно так же "упадёт", и точно так же напечатает ошибку.
То же касается и url. По-моему, хорошим тоном было бы сразу дать функции нормальные данные (готовый URL), а не заставлять её пытаться из потенциального мусора создать себе нормальное окружение.
Напоследок, раз уж тут есть какие-то try, то пусть бы функция была throws, а делать ли try! пусть решают уровнем выше.
Я не понимаю, какой массив, из каких строк, и почему что-то нельзя с ним сделать?
Я предлагал читать данные о доменах (видимо для отображения в UI) прямо из Info.plist, причём туда можно записать не только имя домена и флаг NSExceptionAllowsInsecureHTTPLoads, но так же и любые другие пользовательские данные, как тот же description. Да, структура будет чуть другая, ну и что? Вместо массива объектов типа [{ domain, description, flag }] будет структура { domain: { description, flag} }. Попарсить её нет никакой проблемы, зато есть один источник правды.
А что делает эта функция? Ну чёт умножает, чёт сдвигает, чёт отнимает. Но это не ответ.
Суть, которую я хотел донести, состоит в том, что Великолепный Инструмент не обратил внимание на подозрительные части, а безропотно помог лишь ещё сильнее ухудшить и без того стремноватую функцию.
Имхо функция сначала была просто плохой и непонятной, а после этого "патча", она стала совсем плохой и ещё менее понятной для программиста. И проблема не в квалификации читающего. Я изо всех сил пытался удержаться от комментария по поводу "15 лет программирования", но не смог. Мне кажется, за 15 лет такие функции должны начать вызывать неприятные чувства.
Более того, тот "голос", который говорит в моей голове при чтении и осмыслении кода, использует другие "слова", другой порядок, совершенно другой подход. Для меня чтение вот таких объяснений это как слушать лекцию человека с неприятным тебе голосом, или с некомфортным темпом рассказа, или с фокусом совершенно не на то, что тебе интересно.
Как по мне, так функция показывает признаки некоторых более глобальных изъянов, и вот один из них:
"enrich", похоже, сильно зависит от порядка вызова.
ответ наверное должен бы быть
{ a: 21, b: 8, c: 16 }
а этот пример "сломается" на переменной "a", т.к. "c" ещё не определена, хотя будет определена "попозже".
И в чём польза этого текстового описания для кода? Его всё равно надо осмыслить и загрузить себе в мозг, чтобы потом произвести нужное изменение. Так может проще прочитать код?
Global Talent бывает двух типов: "Exceptional" и "Promising". Для пооучения ILR На Promising надо прожить 5 лет, на Exceptional – 3 года.
Про быстродействие чушь какая-то, и вообще в статье много сомнительных заявлений
вроде нужны будут какие-то хаки для нажатия шифта на одной половине, и буквы на другой
Recourse 👌
мне в google stadia было очень дискомфортно в гонки играть из-за задержки, а тут настоящую машину по улице везти
Зачем в работающем приложении на горячую обновлять локализацию? Никто не умрёт, если новая локализация применится при следующем перезапуске. Зато сколько жизни можно сэкономить не поддерживая такую маргинальную фичу.
Итак, вот мой вариант:
мы вроде согласились, что отдельный файл не нужен, поэтому обновляется только Info.plist;
Info.plist по дефолту ищется в текущей рабочей директории, или его можно передать аргументом
-infoPlist
;json с данными может читаться из трёх источников:
updater -from https://....
– URL в интернете;updater -from /local/path/on/disk
– файл на диске;updater -from -
(dash) или же без аргументов – прочитается из stdin.curl url | updater
;cat file | updater
;updater < file
;updater
и ввод с завершающим Ctrd+D;команда для удаления тоже не нужна, т.к. это просто "записать пустой массив", и это можно сделать как
echo "[]" | updater
;сохраняет тот же формат файла Info.plist (xml или бинарный).
Разве что это проблема для тех, кто парсит такие файлы регулярками, но это исправимо.
Ну и что? Никого же не смущает, что в Dictionary и NSDictionary никогда не было никакого порядка.
Похожий, но другой пример проблемы:
Если
do { try f() } catch { fatalError() }
иf()!
это в принципе одно и то же (потому что одинаково напечатается одинаковая ошибка и одинаково упадёт), то здесь же стало хуже. try! Data(...) напечатал бы гораздо больше полезной информации о том, почему же не получилось прочитать данные, чем просто "infoPlistNotFound". Что ещё и не факт, что правда. Файл-то может быть found, но не смочь прочитаться по тысяче причин: недостаточно прав, прочитался только до половины, да чёрт ещё знает почему. Полезная информация, которая могла бы быть в логах, и помочь расследованию, оказывается просто потеряна.Если будет "просто массив строк", то можно его прямо в исходниках и хранить.
Какой ещё порядок элементов? У словаря нет понятия "порядок элементов".
Глядя на код в репозитории, я увидел множество проблем с этим примером. Какие-то касаются кода, какие-то более концептуальные. Я даже и не знаю с чего начать.
Начну пожалуй с любимого:
Обожаю эти
do { try f() } catch { fatalError(error) }
. Почему бы просто не сделатьtry!
– система точно так же "упадёт", и точно так же напечатает ошибку.То же касается и url. По-моему, хорошим тоном было бы сразу дать функции нормальные данные (готовый URL), а не заставлять её пытаться из потенциального мусора создать себе нормальное окружение.
Напоследок, раз уж тут есть какие-то try, то пусть бы функция была throws, а делать ли try! пусть решают уровнем выше.
Я не понимаю, какой массив, из каких строк, и почему что-то нельзя с ним сделать?
Я предлагал читать данные о доменах (видимо для отображения в UI) прямо из Info.plist, причём туда можно записать не только имя домена и флаг NSExceptionAllowsInsecureHTTPLoads, но так же и любые другие пользовательские данные, как тот же description. Да, структура будет чуть другая, ну и что? Вместо массива объектов типа
[{ domain, description, flag }]
будет структура{ domain: { description, flag} }
. Попарсить её нет никакой проблемы, зато есть один источник правды.