Жесткое кодирование строк, которые никогда не изменятся

39

Поэтому, пытаясь написать программу для спряжения глаголов (алгоритмически, а не через набор данных) для французского языка, я столкнулся с небольшой проблемой.

Алгоритм спряжения глаголов на самом деле довольно прост для 17-ти или около того случаев глаголов и работает по определенному шаблону для каждого случая; таким образом, суффиксы сопряжения для этих 17 классов являются статическими и (очень вероятно) не изменятся в ближайшее время. Например:

// Verbs #1 : (model: "chanter")
    terminations = {
        ind_imp: ["ais", "ais", "ait", "ions", "iez", "aient"],
        ind_pre: ["e", "es", "e", "ons", "ez", "ent"],
        ind_fut: ["erai", "eras", "era", "erons", "erez", "eront"],
        participle: ["é", "ant"]
    };

Это интонационные суффиксы для наиболее распространенного класса глаголов во французском языке.

Существуют и другие классы глаголов (неправильных), чьи спряжения также, скорее всего, останутся неизменными в течение следующего столетия или двух. Так как они нерегулярны, их полные спряжения должны быть включены статически, потому что они не могут быть надежно сопряжены с шаблоном (есть также [по моим подсчетам] 32 неправильных числа). Например:

// "être":
    forms = {
        ind_imp: ["étais", "étais", "était", "étions", "étiez", "étaient"],
        ind_pre: ["suis", "es", "est", "sommes", "êtes", "sont"],
        ind_fut: ["serai", "seras", "sera", "serons", "serez", "seront"],
        participle: ["été", "étant"]
    };

Я мог бы поместить все это в XML или даже JSON и десериализовать это, когда это необходимо использовать, но есть ли смысл? Эти строки являются частью естественного языка, который меняется, но медленными темпами.

Я обеспокоен тем, что, выполнив «правильный» путь и десериализовав некоторый источник данных, я не только усложнил проблему, которая не должна быть сложной, но я также полностью откатился назад по всей цели алгоритмический подход: не использовать источник данных! В C # я мог бы просто создать класс в namespace Verb.Conjugation(например class Irregular) для размещения этих строк в перечисляемом типе или что-то в этом роде, вместо того, чтобы вставлять их в XML и создавать class IrregularVerbDeserializer.

Поэтому вопрос: уместно ли жестко строк кода, которые очень маловероятно , чтобы изменения в течение жизни приложения? Конечно, я не могу гарантировать 100%, что они не изменятся, но риск против стоимости почти тривиален в моих глазах - жесткое кодирование - лучшая идея здесь.

Изменить : предложенный дубликат спрашивает, как хранить большое количество статических строк , в то время как мой вопрос, когда я должен жестко кодировать эти статические строки .

Крис Сирефице
источник
26
Можете ли вы использовать это программное обеспечение для другого языка, кроме французского в будущем?
10
Алгоритмический подход или нет, ясно, что вам просто нужно жестко кодировать эти строки 32 * 20 (и больше, когда вы добавляете больше языков), и единственный реальный вопрос - где их разместить. Я бы выбрал там, где вам удобнее, что звучит так, как будто бы в коде пока что. Вы всегда можете перетасовать их позже.
Ixrec
1
@ChrisCirefice Это звучит довольно оптимально для меня. Действуй.
Ixrec
2
@Gusdor Я не думаю, что вы читаете ясно - я сказал, что шаблоны сопряжения , вероятно, никогда не изменятся или изменятся настолько редко, что перекомпиляция каждые 100 лет или около того будет хорошей. Конечно, код изменится, но как только строки появятся там, как я хочу, если я не буду рефакторинг, они будут статичными в течение следующих 100 лет.
Крис Cirefice
1
+1. Не говоря уже о том, что через 60-100 лет стоимость либо не будет существовать, либо была заменена на лучшую версию в целом.
HarryCBurn

Ответы:

56

уместно ли это для строк с жестким кодом, которые вряд ли изменятся в течение жизни приложения? Конечно, я не могу гарантировать 100%, что они не изменятся, но риск против стоимости почти тривиален в моих глазах - жесткое кодирование - лучшая идея здесь

Мне кажется, что вы ответили на свой вопрос.

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

Я бы использовал самый простой подход для реализации, пока не нашел вескую причину усложнить его.

Дэн Пичельман
источник
Спасибо Дэн, это то, что я понял. Написание XML-схемы для этого, наличие другого файла для отслеживания и необходимость написания интерфейса для десериализации данных просто выглядело излишним, учитывая, что строк не так уж и много, и, поскольку это естественный язык, вряд ли он кардинально изменится. в ближайшие 100 лет. К счастью, в настоящее время в языках программирования у нас есть причудливые способы абстрагирования этих необработанных данных за симпатичный интерфейс, например, French.Verb.Irregular.Etreкоторый будет содержать данные из моего вопроса. Я думаю, что это хорошо работает;)
Крис Cirefice
3
+1 Здесь, из лагеря Ruby, я бы начал что-то хардкодировать и переносить в конфигурацию по мере необходимости. Не преждевременно перегружайте свой проект, делая вещи настраиваемыми. Это только замедляет тебя.
Overbryd
2
Примечание: некоторые группы имеют другое определение «жесткого кодирования», поэтому имейте в виду, что этот термин означает несколько вещей. Существует хорошо известный анти-шаблон, в котором вы жестко кодируете значения в операторах функции, а не создаете структуры данных, как у вас ( if (num == 0xFFD8)). Этот пример должен стать чем-то похожим if (num == JPEG_MAGIC_NUMBER)почти во всех случаях для удобства чтения. Я просто указываю на это, потому что слово «жесткое кодирование» часто поднимает волоски на шеях людей (таких как моя) из-за этого альтернативного значения слова.
Корт Аммон
@CortAmmon JPEG имеет много волшебных чисел. Конечно JPEG_START_OF_IMAGE_MARKER?
user253751
@immibis Ваш постоянный выбор имени, вероятно, лучше моего.
Корт Аммон
25

Вы рассуждаете не в том направлении.

Вы не закодировали только отдельные глаголы. Вы жестко закодировали язык и его правила . Это, в свою очередь, означает, что ваше приложение не может быть использовано для какого-либо другого языка и не может быть расширено другими правилами.

Если это ваше намерение (то есть использовать его только для французского языка), то это правильный подход, потому что YAGNI. Но вы признаете, что хотите использовать его позже и для других языков, что будет означать, что очень скоро вам все равно придется перенести все жестко закодированные части в файлы конфигурации. Остается вопрос:

  • Будете ли вы с уверенностью, близкой к 100%, в ближайшем будущем распространять приложение на другие языки? Если это так, вы должны были экспортировать вещи в файлы JSON или XML (для слов, частей слов и т. Д.) И динамические языки (для правил) прямо сейчас, вместо того, чтобы заставлять себя переписывать основную часть вашего приложения.

  • Или существует лишь небольшая вероятность того, что приложение будет расширено где-то в будущем, и в этом случае YAGNI диктует, что самый простой подход (тот, который вы используете прямо сейчас) лучше?

В качестве иллюстрации возьмите проверку правописания в Microsoft Word. Как вы думаете, сколько вещей запрограммировано?

Если вы разрабатываете текстовый процессор, вы могли бы начать с простым орфографическим двигателем с HARDCODED правил и даже HARDCODED словом: if word == "musik": suggestSpelling("music");. Быстро, вы начнете перемещать слова, а затем будете править вне вашего кода. Иначе:

  • Каждый раз, когда вам нужно добавить слово, вы должны перекомпилировать.
  • Если вы узнали новое правило, вы должны изменить исходный код еще раз.
  • И что еще более важно, вы не сможете адаптировать движок к немецкому или японскому языку без написания огромного количества кода.

Как вы подчеркнули себя:

Очень мало правил из французского языка могут быть применены к японскому языку.

Как только вы жестко закодируете правила для языка, каждому другому потребуется все больше и больше кода, особенно учитывая сложность естественных языков.

Другой вопрос, как вы выражаете эти разные правила, если не через код. В конечном счете, вы можете обнаружить, что язык программирования - лучший инструмент для этого. В этом случае, если вам нужно расширить движок, не перекомпилируя его, динамические языки могут быть хорошей альтернативой.

Арсений Мурзенко
источник
1
Ну, конечно, там не все жестко запрограммировано: P, так что я думаю, что все сводится к определению того, как я хочу, чтобы интерфейс выглядел так, чтобы я мог применить его к нескольким языкам. Проблема в том, что я еще недостаточно хорошо знаю все языки, так что это практически невозможно. Я думаю, что одна вещь, которую вы , возможно , упускаете, это то, что шаблоны сопряжения (это все, о чем я говорю) очень статичны в языке, и это действительно то, что в каждом конкретном случае. Существует около 17 моделей спряжения на французском языке для глаголов. Это не будет продолжаться в ближайшее время ...
Крис Cirefice
4
Я не согласен - я не думаю, что имеет смысл перемещать что-либо за пределы кода, прежде чем это произойдет естественным путем посредством рефакторинга. Начните с одного языка, добавьте другие - в какой-то момент реализация ILanguageRule поделится достаточным количеством кода, поэтому эффективнее иметь одну реализацию, параметризованную с помощью XML (или другого файла). Но даже тогда вы можете получить японский язык, который имеет совершенно другую структуру. Начать с того, что ваш интерфейс должен быть XML (или аналогичным), нужно только попросить внести изменения в интерфейс, а не в реализацию.
Ptyx
2
Примечание: если вы хотите добавить больше языков, это не означает перемещение языков в файл конфигурации! Вы также можете иметь LanguageProcessorкласс с несколькими подклассами. (По сути, «файл конфигурации» на самом деле является классом)
user253751
2
@MainMa: почему вы считаете проблемой перекомпиляцию при добавлении слова? Вы все равно должны перекомпилировать, когда делаете какие-либо другие изменения в коде, и список слов, вероятно, является частью кода, которая с наименьшей вероятностью изменится со временем.
JacquesB
3
Я подозреваю, что гибкость возможности кодировать очень специфические грамматические правила каждого языка в подклассе будет в конечном итоге более удобной, чем возможность каким-либо образом загружать те же самые правила из файла конфигурации (потому что вы в основном пишете свой собственный язык программирования для интерпретации конфигураций).
Дэвид К
15

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

Например:

  • Извлечение текстов пользовательского интерфейса в файлы ресурсов. Это позволяет не программисту редактировать и корректировать тексты, и это позволяет добавлять новые языки, добавляя новые локализованные файлы ресурсов.

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

  • Проверка орфографии, в которой есть словарь слов для проверки. Вы можете добавлять новые слова и языки без изменения логики программы.

Но есть также сложности с извлечением в конфигурацию, и это не всегда имеет смысл.

Строки могут быть жестко закодированы, когда фактическая строка не может измениться без изменения логики программы.

Примеры:

  • Компилятор для языка программирования. Ключевые слова не извлекаются в конфигурацию, поскольку каждое ключевое слово имеет определенную семантику, которая должна поддерживаться кодом в компиляторе. Добавление нового ключевого слова всегда требует изменения кода, поэтому нет смысла извлекать строки в файл конфигурации.
  • Реализация протокола: например, HTTP-клиент будет иметь жестко закодированные строки, такие как «GET», «тип контента» и т. д. Здесь эти строки являются частью спецификации протокола, поэтому они являются частями кода, которые с наименьшей вероятностью изменятся.

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

Если вы добавляете новый язык, вам все равно нужно будет добавить новый код, поскольку каждый язык имеет определенную логику сопряжения.


Некоторые полагают, что вы можете добавить какой-то механизм правил, который позволяет вам задавать правила сопряжения для произвольных языков, чтобы новые языки могли добавляться исключительно по конфигурации. Прежде чем идти по этому пути, тщательно подумайте, потому что человеческие языки удивительно странные, поэтому вам нужен очень выразительный механизм правил. Вы бы в основном изобрели новый язык программирования (сопряженный DSL) для сомнительной выгоды. Но у вас уже есть язык программирования, который может делать все, что вам нужно. В любом случае, ЯГНИ.

JacquesB
источник
1
На самом деле, в комментарии к MainMa я упомянул, что писать DSL для этого было бы бессмысленно, потому что очень немногие естественные языки достаточно похожи, чтобы стоить усилий. Может быть, французский / испанский / итальянский язык будет достаточно близким , но на самом деле не стоит дополнительных усилий, учитывая, что количество правил очень статично в любом языке. Другие моменты, которые вы упоминаете о сложности, были моими точными заботами, и я думаю, что вы прекрасно поняли то, что я спрашивал в моем вопросе, и дали отличный ответ с примерами, так что +1!
Крис Cirefice
5

Я полностью согласен с ответом Дэна Пихельмана, но я хотел бы добавить одну вещь. Вопрос, который вы должны задать себе здесь: «кто будет поддерживать / расширять / исправлять список слов?». Если это всегда человек, который также поддерживает правила определенного языка (конкретный разработчик, я полагаю, вы), то нет смысла использовать внешний файл конфигурации, если это усложняет ситуацию - вы не получите никакой выгоды от это. С этой точки зрения, имеет смысл жестко закодировать такие списки слов, даже если вам придется время от времени изменять их, если этого достаточно для доставки нового списка как части новой версии.

(С другой стороны, если есть небольшая вероятность, что кто-то другой должен иметь возможность поддерживать список в будущем, или если вам нужно изменить списки слов без развертывания новой версии вашего приложения, используйте отдельный файл.)

Док Браун
источник
Это хороший момент - однако, я очень вероятно, что я буду единственным человеком, который фактически будет поддерживать код, по крайней мере, в течение следующих нескольких лет. Хорошая часть этого заключается в том, что, хотя строки будут жестко закодированы, это очень маленький набор строк / правил, которые вряд ли изменятся в ближайшее время (поскольку это естественный язык, который не эволюционирует год от года к -год). Тем не менее, правила спряжения, строки завершения глагола и т. Д., По всей вероятности, будут одинаковыми для нашей жизни :)
Крис Сирфице
1
@ChrisCirefice ": именно моя точка зрения.
Док Браун
2

Даже несмотря на то, что здесь жесткое кодирование выглядит хорошо и лучше, чем динамическая загрузка файлов конфигурации, я все же рекомендую вам строго отделить ваши данные (словарь глаголов) от алгоритма . Вы можете скомпилировать их прямо в ваше приложение в процессе сборки.

Это избавит вас от хлопот с ведением списка. В вашей VCS вы можете легко определить, действительно ли коммит изменил алгоритм, или просто исправить ошибку сопряжения. Кроме того, список может потребоваться добавить в будущем для случаев, которые вы не рассматривали. В частности, число 32 неправильных глаголов, которые вы сосчитали, не кажется точным. В то время как те, кажется, покрывают обычно используемые, я нашел ссылки на 133 или даже 350 из них.

Берги
источник
Берги, я планировал отделить данные от алгоритма. Что вы заметили о нерегулярных французских - определение нерегулярности понимается в лучшем случае. Что я имею в виду, когда говорю « неправильный» - это глаголы, которые нельзя «вычислить» или спрягать из одной только их инфинитивной формы. Нерегулярные глаголы вообще не имеют определенного паттерна и, следовательно, должны четко указывать их спряжения (например, в French.Verb.Conjugation.Irregular`). Технически, глаголы -ir «неправильные», но на самом деле они имеют фиксированную форму спряжения :)
Крис Сирфице
0

Важной частью является разделение интересов. То, как вы этого достигнете, менее актуально то есть Java в порядке.

Независимо от того, как выражены правила, нужно ли вам добавлять язык изменения правила: сколько кода и файлов нужно отредактировать?

В идеале, добавление нового языка должно быть возможно либо путем добавления файла «english.xml», либо нового объекта «EnglishRules реализует ILanguageRules». Текстовый файл (JSON / XML) дает вам преимущество, если вы хотите изменить его вне жизненного цикла сборки, но при этом требуется сложная грамматика, синтаксический анализ и отладка будет сложнее. Файл кода (Java) позволяет вам выразить сложные правила более простым способом, но требует перестройки.

Я бы начал с простого Java API за чистым языковым интерфейсом, который вам нужен в обоих случаях. Вы всегда можете добавить реализацию этого интерфейса, поддерживаемую XML-файлом позже, если хотите, но я не вижу необходимости решать эту проблему немедленно (или когда-либо).

ptyx
источник