Пытаемся. Наиболее инициативные товарищи образовали т.н. «Совет Эльфов», который принимал все судьбоносные решения подобного рода. Но всегда есть несколько человек, с которыми ничего не поделать. Или встают в позу, или отмахиваются, или просто не видят проблемы. Вот тут бы, на мой взгляд, как раз и стоило бы слегка надавить «административным ресурсом», которым совет не обладает :)
Я не руководитель, опыт у меня и правда небольшой (да еще в одной компании), я просто вижу проблемы вокруг себя. У нас даже просто сидящие в разных концах комнаты люди умудрялись развивать маленькие фабрики велосипедов, несовместимые друг с другом. Просто потому, что они не общались. Каждый сидит в своем углу и делает свое маленькое дело. Что происходит, когда люди сидят в разных комнатах — я вообще молчу.
Отмечу, что у нас своя специфика, очень много небольших проектов, поэтому разработчикам существенно проще не контактировать друг с другом. Но тем не менее.
Если вы решаете за сотрудников как им работать — вы не команда. Вы спускаете сверху git flow, список статусов задач, рабочие часы с 9:00 до 18:00?
Мой небольшой опыт показывает, что если кто-нибудь (необязательно РМ или начальство, просто кто-то, кому не все равно) не придумает, как организовывать работу (банально, конвенции по именованию файлов/директорий, конвенции по кодированию, rebase или merge и т.д.), то все будут делать это как попало. Если всех не приучить юзать git, то у кого-то вообще никакого версирования не будет, кто-то будет архивчики руками делать ежедневно, кто-то svn себе поставит. И код будет расползаться просто файлами по скайпу.
Возможно, если у вас уже есть настоящая команда, в которой все сознательные и рациональные люди, то они видят эту проблему и решают ее сообща, но в реальности таки придется некоторые вещи педалировать сверху, иначе будет просто помойка.
Хотелось бы задать завуалированный вопрос не по статье. Но сперва предыстория:
Около 8 часов мы с коллегой искали баг, который проявлялся в весьма запутанной ситуации. Когда мы его наконец нашли и тщательно побились головой об стол, проклиная свою глупость. И я, разумеется, поднимаю палец в верх и говорю своему коллеге: «А знаешь, как мы могли бы найти этот баг легко? (драматическая пауза) PVS-Studio!»
Да, я очень давно пытаюсь убедить своих коллег в необходимости использования PVS-Studio.
На этот раз мы таки взяли себя в руки, поставили, запустили проверку и… баг не нашелся. И вот это было довольно обидно, если честно.
checkSomeCondition — функция с побочными эффектами, которая, как вы уже понимаете, не вызывалась второй раз, если первая проверка возвращала false. Этот код писал я сам (и мне стыдно) и в тот момент я просто напрочь забыл об этом свойстве оператора &&. И, формально, это в общем-то и не баг даже, подобный код можно писать намеренно.
Тем не менее, хотелось бы узнать, рассматривался ли подобный код в кандидаты на предупреждение? Можно ли как-нибудь это предупреждение получить? Допустим, если у функции нет атрибута pure?
Комментарий для модуля был весьма абстрактный — «Тут описан такой-то класс, он делает вот это». Какого-то единого метакомментария для всего проекта я не обнаружил. Возможно, конечно, я плохо искал…
Судя по git blame комментарии-шапки добавлялись для какого-то генератора биндингов, видимо, некомментированные функции этому генератору были не нужны.
Она возвращает указатель на строку. Эту строку нужно освобождать? Или не нужно? Комментариев к функции или внутри функции нет вообще. Строка прямо в ней не формируется, она берется из другой функции.
В итоге из-за отсутствия комментария (банально шапки к функции), приходится не просто читать код этой конкретной функции, а прослеживать весь путь, который эта несчастная строка проходит, прежде чем до моего вызова доберется.
Самая большая моя боль была при первом столкновении с библиотекой, завязанной на glib. Куча функций вообще без единого коммента. Ладно, внутри функций, бог с ним. Но хотя бы о самой функции — что за аргументы, что она возвращает? Нет, зачем, и так же все понятно.
Т.к. многие функции возвращали указатели, постоянно приходилось угадывать, нужно ли потом память по этим указателям освобождать самостоятельно? Или нужно вызывать g_object_unref? Или можно вообще ничего не делать?
Ох и намаялся я, пока все утечки памяти выискивал.
Твоё мнение никому не интересно, можешь сколько угодно распинаться о том как по твоему надо делать, о розовых пони и прочих галлюцинациях.
Я же тебе предложил: иди и сделай, покажи как надо — тогда будет о чём подумать, пока ты очередной теоретег.
Мне кажется, что вы грубите мне несколько необоснованно. И откуда вы знаете, кому мое мнение интересно, а кому нет? Поэтому говорите, пожалуйста, только за себя.
Я не криптограф и не считаю себя достаточно квалифицированным специалистом, чтобы писать криптографические библиотеки. Однако это не мешает мне чувствовать code smell.
Реальный код это всегда компромисс между: скоростью работы, потребляемыми ресурсами, временем разработки, безопасностью, читаемостью, соблюдением кодстайла, писаниной тестов и документации и тд.
Это утверждение верно. Но в зависимости от области применения этого кода компромисс достигается в разных точках. Сайтик в интернете для 10 друзей можно делать как угодно, но от кода в медицинской или автомобильной технике зависят человеческие жизни! И там надежность играет (или, по крайней мере, должна играть) несколько большую роль, чем количество табуляций или скорость разработки. От криптографии зависят приватность и очень чувствительные данные людей, а иногда и жизнь/свобода.
Если ты такой идеалист оторванный от реальности, иди разгребай авгиевы конюшни в том же OpenSSH, потом будешь рассказывать про аккуратность, гото, мисра и прочие мастхэв идеалиста.
А, ну правильно, в openssh конюшни и дальше будем такие же конюшни разводить, прально.
Конечно, табуляция ведь гораздо важнее чем чистота кода!
И супер-пупер защищенная от квантовых компьютеров криптография будет за границы массивов выходить. Ну ок, на здоровье.
А что надо на крестах или ГОмосятине какой писать?
goto тоже нормальная практика для err_out/cleanup потому что 100500 проверок и только одно место для очистки всего сразу.
Я не буду говорить про Rust, но можно и на крестах, вообще-то. По крайней мере, типизация построже будет, а публичное API все равно extern «C».
На мой взгляд, goto — это не нормальная практика, это признак слабости и крохоборства :) Всегда можно написать без goto. И это не микроконтроллер с килобайтом памяти, чтобы там так байты и такты экономить.
На мой взгляд, опять-таки, криптографию нужно писать очень, очень, очень аккуратно, вплоть до MISRA C. А MISRA учит нас, что
Rule 14.4 (required): The goto statement shall not be used
По своему опыту могу сказать, что если в коде есть goto, то дальше ожидать можно чего угодно — игнорирования strict aliasing, касты через union, сдвиги отрицательных чисел влево и черт знает что еще.
Компания Microsoft тоже не осталась в стороне и в 2016 году выпустила библиотеку SIDH(Supersingular Isogeny Key Exchange) с открытым исходным кодом. Одним из преимуществ данной библиотеки является возможность использования эллиптических кривых в форме Монтгомери, которые защищают от атак по времени.
Вау, подумал я. Круто!
SIDH реализована на языке C
Oh wait…
if (CurveIsogeny == NULL) {
Status = CRYPTO_ERROR_NO_MEMORY; goto cleanup;
}
А есть какие-нибудь исследования на тему того, как же все-таки читают саванты? Которые одним взглядом всю страницу окидывают?
Как у них глаза успевают вообще весь текст пробежать?
Сделать хороший текстовый конфиг — тоже не так-то просто, на самом деле.
Помнится, пришлось мне пользоваться одной САПР, которая настройки в файле хранила…
Настроек было пару тысяч, изначально в файле присутствовала пара сотен.
Настройки назывались типа «allow_harn_mfg_assy_retrieval » или «style_grid_spacing». Разумеется, среди них были ну очень похожие по названию, но совсем разные по действию.
То, что в файле уже было, не было отсортировано по алфавиту или еще как-то сгруппировано, просто все подряд навалено.
Некоторые опции конфликтовали друг с другом.
Разумеется, существовали огромные талмуды, где перечислялись все возможные опции, только надо было тщательно смотреть на соответствие версии талмуда и версии САПРа, потому что старые опции переставали работать, зато появлялись новые.
Причем я так и вижу, что давным-давно этих опций было штук 10 и кто-то подумал — «Да лааадно, и так вроде все понятно».
Прошу прощения, если не по адресу, но очень меня такой вопрос интересует — а чем безопасно мыть, скажем, ванну, восстановленную акрилом? А то повсюду довольно противоречивая информация, то можно кислотными средствами, то ни в коем случае.
Однозначно нельзя абразивами, в это я верю, а вот насчет кислот-щелочей очень интересно (ибо просто мылом или фейри отмывается она не очень).
Я просто подумал, что вы предлагаете в папке include дублировать всю структуру каталогов для исходников, а не держать там только глобальные заголовочники. Если в папку include не совать вообще все заголовочные файлы, а только глобальные, то никаких возражений у меня нет.
А не могли бы вы объяснить, какой смысл делать отдельную директорию include? Я в этом вижу только минусы:
нужно прописывать еще один путь в настройках проекта
дерево проекта увеличивается вдвое, ведь внутри папки include приходится повторять всю структуру папок с файлами .c
в файле xx.c нельзя просто написать include «xx.h», приходится писать полный путь до него — #include «yyy/zzz/xx.h»
чтобы скопировать какой-то «модуль», вам приходится копировать два файла из разных мест
Гораздо удобнее, на мой взгляд, группировать файлы в папке по принципу «модулей». Допустим, модуль Common — это отдельная папка, в ней common.c и common.h. Этот модуль приобретает «позиционную независимость», т.е. когда вы его копируете в другой проект, вам не надо переписывать инклуд в файле common.c. Ну и все минусы, описанные выше, пропадают.
Конечно, какой-то разумный предел сверху нужен, не надо позволять делать пароли в килобайт длиной, но 20 символов — это, все-таки, перебор. Даже отдельные слова бывают длиннее.
Вот, скажем, 255 символов — вполне разумный предел.
Отмечу, что у нас своя специфика, очень много небольших проектов, поэтому разработчикам существенно проще не контактировать друг с другом. Но тем не менее.
Мой небольшой опыт показывает, что если кто-нибудь (необязательно РМ или начальство, просто кто-то, кому не все равно) не придумает, как организовывать работу (банально, конвенции по именованию файлов/директорий, конвенции по кодированию, rebase или merge и т.д.), то все будут делать это как попало. Если всех не приучить юзать git, то у кого-то вообще никакого версирования не будет, кто-то будет архивчики руками делать ежедневно, кто-то svn себе поставит. И код будет расползаться просто файлами по скайпу.
Возможно, если у вас уже есть настоящая команда, в которой все сознательные и рациональные люди, то они видят эту проблему и решают ее сообща, но в реальности таки придется некоторые вещи педалировать сверху, иначе будет просто помойка.
Около 8 часов мы с коллегой искали баг, который проявлялся в весьма запутанной ситуации. Когда мы его наконец нашли и тщательно побились головой об стол, проклиная свою глупость. И я, разумеется, поднимаю палец в верх и говорю своему коллеге: «А знаешь, как мы могли бы найти этот баг легко? (драматическая пауза) PVS-Studio!»
Да, я очень давно пытаюсь убедить своих коллег в необходимости использования PVS-Studio.
На этот раз мы таки взяли себя в руки, поставили, запустили проверку и… баг не нашелся. И вот это было довольно обидно, если честно.
В чем же заключался баг?
checkSomeCondition — функция с побочными эффектами, которая, как вы уже понимаете, не вызывалась второй раз, если первая проверка возвращала false. Этот код писал я сам (и мне стыдно) и в тот момент я просто напрочь забыл об этом свойстве оператора &&. И, формально, это в общем-то и не баг даже, подобный код можно писать намеренно.
Тем не менее, хотелось бы узнать, рассматривался ли подобный код в кандидаты на предупреждение? Можно ли как-нибудь это предупреждение получить? Допустим, если у функции нет атрибута pure?
Судя по git blame комментарии-шапки добавлялись для какого-то генератора биндингов, видимо, некомментированные функции этому генератору были не нужны.
Она возвращает указатель на строку. Эту строку нужно освобождать? Или не нужно? Комментариев к функции или внутри функции нет вообще. Строка прямо в ней не формируется, она берется из другой функции.
В итоге из-за отсутствия комментария (банально шапки к функции), приходится не просто читать код этой конкретной функции, а прослеживать весь путь, который эта несчастная строка проходит, прежде чем до моего вызова доберется.
Т.к. многие функции возвращали указатели, постоянно приходилось угадывать, нужно ли потом память по этим указателям освобождать самостоятельно? Или нужно вызывать g_object_unref? Или можно вообще ничего не делать?
Ох и намаялся я, пока все утечки памяти выискивал.
Мне кажется, что вы грубите мне несколько необоснованно. И откуда вы знаете, кому мое мнение интересно, а кому нет? Поэтому говорите, пожалуйста, только за себя.
Я не криптограф и не считаю себя достаточно квалифицированным специалистом, чтобы писать криптографические библиотеки. Однако это не мешает мне чувствовать code smell.
Это утверждение верно. Но в зависимости от области применения этого кода компромисс достигается в разных точках. Сайтик в интернете для 10 друзей можно делать как угодно, но от кода в медицинской или автомобильной технике зависят человеческие жизни! И там надежность играет (или, по крайней мере, должна играть) несколько большую роль, чем количество табуляций или скорость разработки. От криптографии зависят приватность и очень чувствительные данные людей, а иногда и жизнь/свобода.
А вообще, толстовато, уважаемый, толстовато.
А, ну правильно, в openssh конюшни и дальше будем такие же конюшни разводить, прально.
Конечно, табуляция ведь гораздо важнее чем чистота кода!
И супер-пупер защищенная от квантовых компьютеров криптография будет за границы массивов выходить. Ну ок, на здоровье.
Я не буду говорить про Rust, но можно и на крестах, вообще-то. По крайней мере, типизация построже будет, а публичное API все равно extern «C».
На мой взгляд, goto — это не нормальная практика, это признак слабости и крохоборства :) Всегда можно написать без goto. И это не микроконтроллер с килобайтом памяти, чтобы там так байты и такты экономить.
На мой взгляд, опять-таки, криптографию нужно писать очень, очень, очень аккуратно, вплоть до MISRA C. А MISRA учит нас, что
По своему опыту могу сказать, что если в коде есть goto, то дальше ожидать можно чего угодно — игнорирования strict aliasing, касты через union, сдвиги отрицательных чисел влево и черт знает что еще.
Вау, подумал я. Круто!
Oh wait…
Ну блин, опять пошло-поехало…
Как у них глаза успевают вообще весь текст пробежать?
Помнится, пришлось мне пользоваться одной САПР, которая настройки в файле хранила…
Причем я так и вижу, что давным-давно этих опций было штук 10 и кто-то подумал — «Да лааадно, и так вроде все понятно».
Так и не удалось мне рамку по ГОСТу сделать.
Однозначно нельзя абразивами, в это я верю, а вот насчет кислот-щелочей очень интересно (ибо просто мылом или фейри отмывается она не очень).
Я просто подумал, что вы предлагаете в папке include дублировать всю структуру каталогов для исходников, а не держать там только глобальные заголовочники. Если в папку include не совать вообще все заголовочные файлы, а только глобальные, то никаких возражений у меня нет.
А не могли бы вы объяснить, какой смысл делать отдельную директорию include? Я в этом вижу только минусы:
Гораздо удобнее, на мой взгляд, группировать файлы в папке по принципу «модулей». Допустим, модуль Common — это отдельная папка, в ней common.c и common.h. Этот модуль приобретает «позиционную независимость», т.е. когда вы его копируете в другой проект, вам не надо переписывать инклуд в файле common.c. Ну и все минусы, описанные выше, пропадают.
Вот, скажем, 255 символов — вполне разумный предел.