Лучше, более простой пример 'семантического конфликта'?

Мне нравится отличать три различных типов конфликта от системы управления версиями (VCS):

  • текстовый
  • синтаксический
  • семантический

Текстовый конфликт является тем, который обнаруживается процессом обновления или слиянием. Это отмечается системой. Фиксация результата не разрешена VCS, пока конфликт не разрешен.

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

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

Мой пример семантического конфликта использует SVN (Подверсия) и C++, но тот выбор не действительно относится к сущности вопроса.

Основной код:

int i = 0;
int odds = 0;
while (i < 10)
{
    if ((i & 1) != 0)
    {
        odds *= 10;
        odds += i;
    }
    // next
    ++ i;
}
assert (odds == 13579)

Левое (L) и Право (R) изменения следующие.

'Оптимизация' Left (изменяющий значения переменная цикла берет):

int i = 1; // L
int odds = 0;
while (i < 10)
{
    if ((i & 1) != 0)
    {
        odds *= 10;
        odds += i;
    }
    // next
    i += 2; // L
}
assert (odds == 13579)

'Оптимизация' права (изменяющийся, как переменная цикла используется):

int i = 0;
int odds = 0;
while (i < 5) // R
{
    odds *= 10;
    odds += 2 * i + 1; // R
    // next
    ++ i;
}
assert (odds == 13579)

Это - результат слияния или обновления, и не обнаруживается SVN (который является корректным поведением для VCS), таким образом, это не текстовый конфликт. Обратите внимание, что это компилирует, таким образом, это не синтаксический конфликт.

int i = 1; // L
int odds = 0;
while (i < 5) // R
{
    odds *= 10;
    odds += 2 * i + 1; // R
    // next
    i += 2; // L
}
assert (odds == 13579)

assert сбои, потому что odds 37.

Таким образом, мой вопрос следующие. Существует ли более простой пример, чем это? Существует ли простой пример, где скомпилированный исполняемый файл имеет новый катастрофический отказ?

Как вторичный вопрос, там случаи этого, что Вы встретились в реальном коде? Снова, простые примеры особенно приветствуются.

11
задан Rhubbarb 25 March 2010 в 10:02
поделиться

1 ответ

Придумывать простые релевантные примеры не очевидно, и этот комментарий лучше всего резюмирует, почему:

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

[Это в основном то, что иллюстрирует ваш пример]

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

На самом деле, я бы сказал, что слияние - отвлекающий маневр:
такого рода семантическое столкновение между разрозненными, но взаимозависимыми частями кода неизбежно в тот момент, когда они могут развиваться по отдельности.
Как организован этот параллельный процесс разработки - DVCS; CVCS; архивы и патчи; все редактируют одни и те же файлы в общей сетевой папке - это не имеет никакого значения.
Слияние не вызывает семантических конфликтов, программирование вызывает семантические конфликты.

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


При этом, самый простой пример, как показано Мартином Фаулером в его статье Feature Branch , - это переименование метода:

Проблема, о которой я больше всего беспокоюсь, - это семантический конфликт.
Простым примером этого является то, что профессор Плам изменяет имя метода, который вызывает код преподобного Грина. Инструменты рефакторинга позволяют безопасно переименовывать метод, но только на основе вашего кода.
Итак, если G1-6 содержит новый код, вызывающий foo, профессор Плам не может сказать об этом в своей базе кода, поскольку у него его нет. Вы узнаете только о большом слиянии.

Переименование функции - относительно очевидный случай семантического конфликта.
На практике они могут быть гораздо более тонкими.

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


Как Оле Линге упоминает в своем ответе (проголосовало), Мартин Фаулер действительно написал сегодня (время этого редактирования) сообщение о «семантическом конфликте» , включая следующую иллюстрацию:

semantic conflict illustration

Опять же, это основано на переименовании функции, хотя упоминается более тонкий случай, основанный на внутреннем рефакторинге функции:

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

Итак, во-первых, какими бы мощными ни были ваши инструменты, они защитят вас только от текстовых конфликтов.

Однако есть несколько стратегий, которые могут существенно помочь нам справиться с ними

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

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

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

8
ответ дан 3 December 2019 в 09:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: