Pull to refresh
18
0
Алексей Сторожев @storoj

User

Send message
float wtf( float number )
{
 long i;
 float x2, y;
 const float threehalfs = 1.5F;

 x2 = number * 0.5F;
 y  = number;
 i  = * ( long * ) &y;
 i  = 0x5f3759df - ( i >> 1 );
 y  = * ( float * ) &i;
 y  = y * ( threehalfs - ( x2 * y * y ) );
 return y;
}

А что делает эта функция? Ну чёт умножает, чёт сдвигает, чёт отнимает. Но это не ответ.

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

Имхо функция сначала была просто плохой и непонятной, а после этого "патча", она стала совсем плохой и ещё менее понятной для программиста. И проблема не в квалификации читающего. Я изо всех сил пытался удержаться от комментария по поводу "15 лет программирования", но не смог. Мне кажется, за 15 лет такие функции должны начать вызывать неприятные чувства.

Более того, тот "голос", который говорит в моей голове при чтении и осмыслении кода, использует другие "слова", другой порядок, совершенно другой подход. Для меня чтение вот таких объяснений это как слушать лекцию человека с неприятным тебе голосом, или с некомфортным темпом рассказа, или с фокусом совершенно не на то, что тебе интересно.

Как по мне, так функция показывает признаки некоторых более глобальных изъянов, и вот один из них:

"enrich", похоже, сильно зависит от порядка вызова.

let object = { a: 1, b: 2, c: 3 }
enrich(object, "a", "c+5")
enrich(object, "c", "b+b")
enrich(object, "b", "8")

ответ наверное должен бы быть { a: 21, b: 8, c: 16 }

let object = { a: 1, b: 2 }
enrich(object, "a", "c+5")
enrich(object, "c", "b+b")
enrich(object, "b", "8")

а этот пример "сломается" на переменной "a", т.к. "c" ещё не определена, хотя будет определена "попозже".

И в чём польза этого текстового описания для кода? Его всё равно надо осмыслить и загрузить себе в мозг, чтобы потом произвести нужное изменение. Так может проще прочитать код?

Global Talent бывает двух типов: "Exceptional" и "Promising". Для пооучения ILR На Promising надо прожить 5 лет, на Exceptional – 3 года.

Про быстродействие чушь какая-то, и вообще в статье много сомнительных заявлений

вроде нужны будут какие-то хаки для нажатия шифта на одной половине, и буквы на другой

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

Зачем в работающем приложении на горячую обновлять локализацию? Никто не умрёт, если новая локализация применится при следующем перезапуске. Зато сколько жизни можно сэкономить не поддерживая такую маргинальную фичу.

Итак, вот мой вариант:

import Foundation

let infoPlistURL = URL(fileURLWithPath: UserDefaults.standard.string(forKey: "infoPlist") ?? "Info.plist")

var format: PropertyListSerialization.PropertyListFormat = .xml
var plist = try! PropertyListSerialization
  .propertyList(from: try! Data(contentsOf: infoPlistURL),
                options: .mutableContainersAndLeaves,
                format: &format) as! NSMutableDictionary

let kvPairs = try JSONDecoder()
  .decode([DomainInfo].self, from: try readDomainsData())
  .map {
    ($0.name, [
      "NSExceptionAllowsInsecureHTTPLoads": $0.allowsInsecureHTTPLoads,
      "MyDescription" : $0.description
    ])
  }

plist["NSAppTransportSecurity"] = [
  "NSExceptionDomains": Dictionary(uniqueKeysWithValues: kvPairs)
]

try! PropertyListSerialization
  .data(fromPropertyList: plist, format: format, options: 0)
  .write(to: infoPlistURL)

struct DomainInfo: Decodable {
  let name: String
  let allowsInsecureHTTPLoads: Bool
  let description: String
}

func readDomainsData() throws -> Data {
  if let url = UserDefaults.standard.string(forKey: "from"), url != "-" {
    if url.hasPrefix("http://") || url.hasPrefix("https://") {
      return try Data(contentsOf: URL(string: url)!)
    }
    return try Data(contentsOf: URL(fileURLWithPath: url))
  }
  return FileHandle.standardInput.readDataToEndOfFile()
}
  • мы вроде согласились, что отдельный файл не нужен, поэтому обновляется только 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 никогда не было никакого порядка.

Похожий, но другой пример проблемы:

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} }. Попарсить её нет никакой проблемы, зато есть один источник правды.

Information

Rating
Does not participate
Location
London, England - London, Великобритания
Date of birth
Registered
Activity

Specialization

Mobile Application Developer