Pull to refresh
37
0.9

Пользователь

Send message

В 2012 меня пригласили в один околомедицинский стартар из долины. Хотя я был приглашён сделать один весьма низкоуровневый механизм, которым стали бы пользоваться люди, занимающиеся бизнес-логикой, и оставить им его, я сам остался в проекте и тоже стал заниматься бизнес-логикой.

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

В какой-то момент в проект вернулся человек, который у руководителя проекта имел репутацию очень крутого программиста, и который в данном проекте был родоначальником кодовой базы, потом был тимлидом, когда у него появились подчинённые программисты, а потом оставил проект. Когда он, вернувшись, увидел мои нововведения в плане БД, он был в бешенстве. Руководитель проекта к моим новшествам относился скептически, этот бывший вернувшийся тимлид — резко негативно. Ох, сколько агрессивных баталий пришлось пройти, чтобы отстоять точку зрения, что СУБД должна сопротивляться попыткам запихнуть в неё ахинею. Чего я только не наслушался: что я отстал от жизни, что изобретаю велосипед, что это не соответствует современным канонам и портит весь проект... И, мол, тебя ведь пригласили писать низкоуровневые вещи и под дизассемблером реверсить то, что нам нужно — зачем ты суёшься в дизайн БД.

И это медицинский продукт, Карл! Одна забытая или неправильно проведённая проверка — и вот одна и та же машина скорой помощи с одним и тем же экипажем в одно и то же время должна ехать к двум совершенно разным пациентам в разных концах города. А там все проверки (те что на уровне PHP-бэкенда и в WET-духе при этом) были сделаны так, будто мир однопоточен и параллельно обрабатываемых бэкендом запросов и быть не может.

Оба фактора могут присутствовать одновременно.

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

Что-то с трудом верится про микроволновку. Там такой фейлсейф...

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

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

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

Окей, глупость сморозил: я посчитал, что для формы


Bar(...);

под капотом вызывается operator new, хотя на самом деле экземпляр порождается на стеке и оператор new не вызывается.


Я точно знаю, что за А + Б скрывается вызов оператора + с аргументами А и Б

Нет, вы точно не знаете, что именно там вызывается. Возможно A и Б является числовыми переменными и происходит обычная арифметическая операция, а возможно это экземпляры классов (разных или одинаковых), для которых определён свой оператор сложения, а возможно они экземпляры классов, но для них определён operator int(), и два объекта приводятся к типу int и совершается банальная арифметика, а возможно только один из объектов приводится к типу int, потому что существует оператор сложения, работающий с классом и int в роли операндов.


Просто глядя на место в коде, где находится А+Б, вы не знаете заранее и наверняка, какая комбинация из приведений типов будет задействована и какая будет реализация оператора сложения будет вызвана.


В Си без плюсов вы знаете, что за А+Б стоит сложение с применением целочисленной или FP-арифметики. И (распространяя и обобщая), что если в коде вашей функции нет явных вызовов других функций, то говоря о результирующем машинном коде, там не будет инструкции CALL или заинлайненного кода какой-то другой функции. Зависимости и побочные эффекты очевидны. Но не в С++.

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


Ну не храните воду в асбестовых кувшинах, на крыше то чем он вреден или в стене?

Мне сейчас вентиляцию в многоквартирном доме делают из асбесто-цементного листа. И как показывает обратный клапан, вентиляция не работает 100% времени как отточная — обратный клапан постоянно перекладывается из открытого положения в закрытое, а значит, если бы я его не установил, 50% времени воздух шёл бы из шахты вентиляции в квартиру.

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


Но главное, что отследив историю изменений кода (например, git blame), вы знаете, что если эту строчку не меняли с момента написания, то суть происходящего здесь тоже не меняется (вызов двух функций). По крайней мере, даже просто окинув взглядом тело функции, где нет никаких Bar(Foo() или же наоборот есть, вы сходу, за долю секунду получаете представления о том, как выглядит call tree для родительской функции: вызывается ли отсюда что-либо ещё (что требует расмотрения, анализа, оптимизацию), или мы на «низшей ступени».


Но если переместиться в мир C++, то и за A+B может стоять что угодно (вплоть до вызова sleep или показ какого-то UI — это конечно пример чудовищного говнодизайна приложения, но эта возможно), и за Bar(Foo()) может скрываться не только вызов функции, но и порождение экземпляра классов Foo или Bar, если вдруг это классы. А за порождением экземпляров может (и будет) скрываться обращение к куче, причём оператор new может быть перегружен и это может оказаться какая-то специальная, возможно не самая эффективная куча. То есть за тем, что выглядит как простой вызов функции, может скрываться что-то, что в 10 000 раз тяжелее, чем простой вызов функции. К тому же, если у конструктора Foo тип аргумента не Bar, а какой-то другой, возможно сработает неявное приведение типа.


В Си то, что выглядит как утка, является уткой.


Скрытый текст

Я не говорю, что то, что я выше написал — это однозначное зло. В конце-концов, иначе С++ оказался бы в аутсайдерах. Но это и не однозначное добро. По крайней мере, это как со старыми жигулями: если там на приборной панели показывается, что давление масла нормальное и температура охлаждающей жидкости в порядке — значит так оно и есть. А примеры из современной техники, когда, скажем, устройство показывает завышенный заряд батареи, чтобы пользователь думал, что устройство способно долго сохранять заряд. Реальный заряд маппится на отображаемый функцией с как бы выгнутым графиком. Зато потом, когда устройство на издыхании, отображаемый процент заряда начинает быстрыми темпами приближаться к нулю.

Проблема в том, что когда вы видите foo+bar в сишном коде, вы знаете, что здесь происходит. Но в cpp-коде то же самое может означать что угодно, за этим может скрываться миллион неочевидных операций. Придётся распутывать клубок наследований, перегрузок.

А зачем? У вас цель в решении задачи, в создании программного продукта, или же в абстрактном следовании фен-шую ради следовании фен-шую?

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

Я ещё со времён висты/семёрки кричал, что все выравнивания элементов везде, где только можно, похерены.

Но все молча проглотили. Хорошая же ОС, аэро-фигаэро, чо там!

может вы работайте в той сфере где без них никуда.

Они нужны, полезны и частоиспользуемы в любой сфере, если только вы не работаете в сфере написания Hello world программ.

5) Перепробовав гору аутсорсерлв, снова хочет все писать сам

Нулевое доверие-это структура

принципа " доверяй, но проверяй’. 

кто-то получает доступ к учетной записи (- ам) пользователя (- ов)

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

Уже сейчас в VR есть интерактивные выставки, где можно увидеть совершенно другой мир: каким его воспринимают слепые, например.

— Ну что, потомки, Марс уже колонизировали? Холодный термояд освоили?

— Нет...

— А что же вы там делаете в своём мире будущего?

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

Написал не менее длинный ответ на этот коммент, и в последний момент он канул в небытие. Слава новому WYSIWYG-редактору Хабра!

Второй раз набирать нет желания: я вообще-то с телефона набирал, так как лежу с температурой 39, палец и так отваливается. Может быть потом

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

При нормальном подходе люди сначала проектируют, потом за изготовление берутся, и в программировании я обычно начинал с мыслительной работы по проектированию будущего программного продукта, и первое, что появлялось из ничего при зачинании новой программы или нового компонента в программе, это были всегда h-файлы. А вам эта стадия не интересна.

Но теперь это — атавизм

Что поменялось «теперь» по сравнению с временами, когда язык создавался? Люди стали ходить на голове? Число Пи достигло значения 8? Поменялась размерность пространства-времени?

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

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

Грубо говоря, когда в обществе долгое время существовал консенсус, что убивать не хорошо, что справедливость это благо, а несправедливость это плохо, и вдруг приходит молодое поколение и внезапно ставит вопрос: «а почему собственно убивать не хорошо?».

Ладно, попробую. Заголовочные файлы это вообще явление из зоны ответственности препроцессора. Никто вас не заставляет их использовать. Можете не пользоваться ими, а объявления всех типов и прототипы всех функций объявлять прямо в своем cpp-файле. Можете вообще всю свою программу, пусть в ней и 200 тысяч строк кода, уместить в одном единственном cpp-файле.

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

Так вот, если у вас 190 штук cpp-файлов, и во всех вы используете структуры VECTOR3D, WAVEHDR, ANOTHERSTRUCT, то в каждом cpp-файле придется иметь объявление этих структур. 190 × 3 объявлений.

И вот здесь, чтобы не плодить 190 копий объявления трёх структур, чтобы уйти от WET-антипаттерна и использовать DRY-принцип, на сцену выходит препроцессорая фича #include, позволяющая повторяющиеся вещи вынести в один файл и избавиться от повторений, за исключением того, что сама директива #include и имя файла, указанное в ней, таки будет повторяться много раз.

То есть это прямо киллер-фича, которую сделали хоть и не только для, но в значительной степени именно для элиминации повторяющегося исходного кода. Что крайне важно не только потому, что не надо тратить время и силы на написание/контраст одинаковых кусков кода, но и позволяет иметь одно место с авторитетным описанием сущности (как гласит принцип DRY), что исключает вероятность при добавлении нового поля в структуру обновить описание её везде, кроме пары мест.

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

И дело-то видимо не в том, что человек против идеи includeинга файлов на стадии препроцессинга или не понимает как эти пользоваться. А дело скорее всего в том, что человек против идеи прототипов функций, а также он испорчен и избалован IDE, которая прячет процесс сборки и представляет его пользователю как нечто непрозрачное, и человек перестает думать отдельно о линковке, отдельно о компиляции каждого отдельного исходного файла независимо от остальных, а начинает считать, что есть некий черный ящик под названием «компилятор C++», который как-то там вызывается один раз сразу на весь проект, видит сразу весь проект, обрабатывает весь проект и выплёвывает готовый исполняемый файл, а раз так, ну уж наверное он может в одном cpp-файле увидеть определение структуры или функции, а встретив упоминание чего-то такого в другом cpp-файле, который ни сном ни духом про первый файл, самостоятельно догадаться, что вот именно из того файла сущности здесь и упоминаются.

Information

Rating
1,964-th
Location
Петропавловск, Северо-Казахстанская обл., Казахстан
Registered
Activity

Specialization

Software Developer, Embedded Software Engineer
Pure C
Assembler
X86 asm
Win32 API
Visual Basic
MySQL
Git
OOP
Electronics Development
Reverse development