LINUX.ORG.RU

Совместное творчество человека и компьютера над кодом

 , ,


0

2

Вопрос философский.

Довольно часто бывает, что IDE помогает генерировать часть кода.

Примеры:

Dreamweaver

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

Здесь у человека и у компьютера есть области ответственности, разделённые пространственно.

Автоматический рефакторинг

В IDE для Java есть автоматический рефакторинг. Мы написали код, который компилируется. Далее нажали на кнопку и - хопс - метод разбился на два. Здесь разделение ответственности идёт по времени - сначала работает человек, потом компьютер. По файлам ответственность не распределена.

Delphi (и другие IDE)

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

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

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

Затея состояла в том, чтобы было два определения:

написанное нами изначально (уж имя модуля мы всегда должны задать)

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

Одним из этапов сборки будет приведение действительного определения в соответствие с реальностью.

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

Один раз я так делал, хотя цель была другой. Я завёл макрос defun-to-file, который генерирует файл с телом функции, а потом выполняет. Это удобно в случае, когда функция генерируется макросом и у неё нет собственного исходника. Имея хотя бы сгенерированный файл с исходником, мы получаем возможность показать место выполнения в стеке, да и посмотреть, что за код сгенерировался, хранить его в системе контроля версий, искать по нему и т.п.. Ещё хорошо при этом писать в докстринге «сгенерировано из макроса такого-то». Вроде это иногда оказывалось полезным.

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

Соответственно, ищу подтверждения или развенчания данной конструкторской идеи.

★★★★★

Последнее исправление: den73 (всего исправлений: 3)

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

Не, изначальное определение ведь будет в одном месте, второй - сгенерированный, ничего страшного в этом нет.

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

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

loz ★★★★★
()

ищу подтверждения или развенчания данной конструкторской идеи.

Какие идеи может быть в голове у днища, не умеющего читать? Только смехотворные ламеросипеды.

anonymous
()
Ответ на: комментарий от loz

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

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

Но тут всё не так просто. Если мы пишем слово «экспорт» в определении, это подразумевает разработку «снизу вверх».

Но бывает ещё разработка «сверху вниз», то файл интерфейса может придти от архитектора уже готовым. В этом случае не годится формировать его при сборке. Нужно его не трогать, а при сборке - _проверять_, все ли заявленные к экспорту имена должным образом определены. Более того, если мы разбиваем определение модуля на часть «что хотели», которая пишется руками, и часть «что получилось», которую делает среда, то экспорты получаются у нас в разных местах в зависимости от принятой методики разработки. Это сильно запутывает дело.

Так и не могу понять, как сделать это идеально.

den73 ★★★★★
() автор топика
Последнее исправление: den73 (всего исправлений: 2)

Но почему-то я не видел, чтобы так делалось.

Потому что в твоем случае нужна не просто версионность в рамках одного хранилища, а бранчевание:

Объект А (пользователь) -> Объект Б (компьютер)
        |
Объект С (готовый)
Предположим, пользователь решит исправить Объект С, с учетом Объекта Б:
Объект Б (компьютер)
        |
Объект С (старый) -> Объект Д (изменен пользователем) -> Объект Е (компьютер)
Т.о. в контексте одного объекта достаточно версионности. В случае проекта со множеством файлов нужны ветки.

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

gh0stwizard ★★★★★
()

Ниасилил, многабуков.

Твоё творчество совместно не с компьютером. А с проектировщиком того ПО, которое ты используешь.

sin_a ★★★★★
()
Ответ на: комментарий от den73

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

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

Чтобы ещё усложнить задачу, после отката начинаешь делать новую версию развития событий: добавляешь новые файлы.

gh0stwizard ★★★★★
()
Последнее исправление: gh0stwizard (всего исправлений: 1)
Ответ на: комментарий от gh0stwizard

Не знаю, насколько я тебя понял. Но как раз я рассматриваю два варианта избежать бранчей.

А) Компьютер и человек вместе пишут в один файл.

Б) Человек пишет в один файл, компьютер в другой, а используется из них только один. Скажем, А.модуль.полное_определение.сделано_компьютером - это лишь документация, сопровождающая файл А.модуль.определение_модуля.сделано_человеком .

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

Откуда возьмутся ещё бранчи, не пойму? Я меняю

файл А.модуль.определение_модуля.сделано_человеком

компилирую его

получается новый

А.модуль.полное_определение.сделано_компьютером

далее делаю коммит. И всё, просто следующая ревизия.

den73 ★★★★★
() автор топика
Последнее исправление: den73 (всего исправлений: 3)
Ответ на: комментарий от den73

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

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

den73 ★★★★★
() автор топика
Ответ на: комментарий от den73

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

Например, флажок «потребовать, чтобы все экспорты были объявлены в интерфейсе модуля».

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

Если не потребовали - это это этап большого взрыва, «се, творю всё новое».

den73 ★★★★★
() автор топика
Ответ на: комментарий от gh0stwizard

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

den73 ★★★★★
() автор топика
Ответ на: комментарий от sin_a

Твоё творчество совместно не с компьютером. А с проектировщиком того ПО, которое ты используешь.

Не суть важно.

den73 ★★★★★
() автор топика

Довольно часто бывает, что IDE помогает генерировать часть кода.

Это — всего лишь признак синтактической импотенции языка. Бороться надо с причиной.

t184256 ★★★★★
()
Ответ на: комментарий от den73

Т.о. все действия будут носить необратимость изменений (откат назад будет попоболью :). Ну, проект твой, делай как получается, потом перепилишь.

gh0stwizard ★★★★★
()
Ответ на: комментарий от gh0stwizard

Т.о. все действия будут носить необратимость изменений.

Так вопрос и был в том, почему все делают именно с необратимыми изменениями, хотя казалось бы, так делать не надо. И я привёл примеры тому. Разве что МП в ./configure устроено по-иному.

Откат не будет тем что ты сказал, если часто коммитить в реп.

den73 ★★★★★
() автор топика
Ответ на: комментарий от t184256

Это — всего лишь признак синтактической импотенции языка. Бороться надо с причиной.

Мне так тоже казалось довольно долго. Потом я получил свободу делать какие угодно DSL и обрадовался: вот, теперь я смогу сделать так, чтобы любое изменение нужно было вносить в одном месте.

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

А также есть принцип KISS. Если делаешь восьмиэтажное МП, то можно попробовать добиться того, чтобы изменения достаточно было внести в одном месте, но будет ничего не понятно и всё смешано в одну кашу.

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

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

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

Это вполне философского уровня тупик.

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

den73 ★★★★★
() автор топика
Ответ на: комментарий от den73

Так вопрос и был в том, почему все делают именно с необратимыми изменениями

Потому что это проще. Пока не приступишь к реализации все кажется простым :)

Я не хочу тебя наставлять на свой путь, просто дал объяснение, что не все так просто как кажется. Да, и те работы, что ты видел не имели тогда того же git. Да, даже сейчас, взяв git ты много не напилишь, потому что libgit вроде как нету (поправьте, если есть либа на си/си++ без вызовов внешних программ).

gh0stwizard ★★★★★
()
Ответ на: комментарий от gh0stwizard

А твой путь в каких-то реальных проектах используется или это только общие соображения?

den73 ★★★★★
() автор топика
Ответ на: комментарий от den73

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

gh0stwizard ★★★★★
()
Ответ на: комментарий от gh0stwizard

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

den73 ★★★★★
() автор топика
Ответ на: комментарий от den73

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

Не знаю, хорошая это аналогия или нет. Взгляни на слои в gimp (photoshop). Каждый слой отображает конечную версию рисунка. В отличие от самого рисования в gimp, где слои можно совмещать, у тебя каждый слой это конечная версия кода, и единственная. Твоя же задача упрощается, когда ты можешь явно указать к какому слою следует обратиться, чтобы вернуть все назад И продолжить от этого момента новую версию [развития событий].

Без бранчевания ты можешь извращаться через rollback, overcommit (дописывания в текующую ветку того, что уже было) и т.п. Может, тебе этот путь будет проще и более понятен. Смысл бранчевания в моем случае: избежать перезаписи кода, взамен сразу же откатившись в нужную точку/ветку+ревизию (она будет последней).

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

Еще раз, это все в общем виде. И читать мысли я пока не умею =)

P.S. Бранчу нужно создавать тогда, когда изменились входные данные (пользователь создал новый файл и от его содержания выхлоп изменился).

gh0stwizard ★★★★★
()
Последнее исправление: gh0stwizard (всего исправлений: 1)
Ответ на: комментарий от gh0stwizard

Да я вроде написал, для чего мне это нужно. Вот в Паскале есть раздел interface, в C есть файл .h. Они изображают «интерфейс» модуля. Это удобно и соответствует концепции сокрытия деталей реализации. И тут мы смотрим в Го и видим, что там нет этого. Если написал имя с большой буквы, то это уже экспорт. А как увидеть интерфейс модуля? Нужен спец. инструмент, который проищет файл и покажет мне интерфейс. Как покажет? Либо на экране, либо в файл выведет. А дальше оказывается, что в этот файл можно вывести ещё и другую информацию о модуле, которую соберёт этот же инструмент, например, комментарии для автодокументации. А дальше удобно следить за эволюцией этого файла отдельно. Потому что поменялся интерфейс - это одно, а поменялась реализация - это другое. Значит, отдельные файлы .h нужны, но поддерживать их руками неохота. Вот это и есть мой use case или, говоря проще, вариант использования.

Я не вижу тут поводов для бранчей. А вопрос в том, нужно ли отделить написанное мной (допустим, общую документацию по модулю) от написанного компьютером (список экспортов и доки к ним) или стоит это свести в один файл?

den73 ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.