Проработав много лет в IT, я тем не менее имею довольно небольшой опыт работы в компаниях производящих программное обеспечение на продажу. В основном доводилось разрабатывать софт для использования только в своей-же организации. А это создаёт определенную специфику. Программист в этом случае оказывается даже не full stack разработчиком, а вообще всем - аналитиком, постановщиком задачи, менеджером проекта, разработчиком, администратором, поддержкой, писателем инструкций и Бог знает кем ещё. Что позволяет руководствоваться только здравым смыслом и своим пониманием задачи без оглядки на общепринятую практику и стандарты компании. Именно такой опыт отступления от норм и правил я и хочу суммировать в этой статье, потому она и называется "вредные советы". Так что, если Вы собираетесь сдавать экзамен по программированию или устраиваетесь на работу в Microsoft, лучше это не читать.

Внешние ключи - зло

Кроме очевидного снижения производительности на пересчете индексов они способны попортить много крови при сопровождении проекта. У меня есть такая практика, когда приходилось подолгу возиться с восстановлением работоспособности базы из-за обилия внешних ключей. То есть, удаление битой и на самом деле ненужной записи превращается в целое мероприятие, так как она связана с десятками записей в других таблицах. Я конечно понимаю - ссылочная целостность. Но обеспечивать её внешними индексами имеет смысл, если базу разрабатывает один человек, а клиентскую программу другой. А если Вы "от скуки на все руки", несвязанные данные в базе появятся только, если Вы же их туда поместите. И что особенно актуально для локальных баз и баз работающих в маленьких одноранговых сетях, где сервером является обычный настольный компьютер - в результате сбоя портится некая запись и факт наличия внешнего ключа начинает приводить к ошибкам. В частности, Firebird плохо переносит аварийное выключение. Так что, стоит ли делать из ссылочной целостности священную корову? Что для Вас хуже - наличие несвязанных записей в базе или непрерывные звонки от пользователей, у которых не работает программа.

Даже первичный ключ необязателен

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

Лишняя таблица не лишняя

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

Лишний код не лишний

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

Работать головой интереснее, чем говорить по телефону

Речь пойдет о юзабилити и, не побоюсь этого слова, эргономике - вещах давно и прочно забытых. Конечно, если Вы пишете софт на продажу, Вам всё равно, как быстро пользователь разберется в интерфейсе. Вы даже делаете доброе дело, помещая на кнопки вместо надписей непонятные значки без всплывающих подсказок - создаёте рабочие места в службе поддержки. Вам также всё равно, сколько времени нужно пользователю на выполнение тех или иных операций, если это происходит не в Вашей организации. Знаю важность таких вещей по опыту работы на почте. В почтовых отделениях всегда очереди и из-за низкой зарплаты крайне малоквалифицированный персонал. Поэтому пользовательский интерфейс должен быть не просто интуитивно понятным, он должен быть очевидным. И "защиту от дурака" нужно прикручивать везде, где только можно. Если есть возможность сделать выбор из списка вместо ввода с клавиатуры - нужно делать. В случаях вроде вышеупомянутой почты критически важна производительность оператора, поэтому совершенно необходимо, чтобы любое действие можно было осуществить только клавиатурой, без мыши - это намного быстрее. Но и мышью тоже - персонал малоквалифицирован. В общем, лучше один раз не полениться - всё тщательно продумать, протестировать, чем потом постоянно объяснять пользователям, где нужная кнопка и как туда быстрее добраться.

Инструкция не комикс

Широко распространено мнение, что инструкции должны быть максимально подробны и богато иллюстрированы скриншотами. Почему-то мало кто задумывается о том, что большое количество картинок разрывает текст на множество мелких фрагментов, разбросанных по огромному объёму этого графического романа. Это делает очень трудным поиск нужного места. Да и общее понимание прочитанного затрудненно, если текст представляет собой разрозненные фразы по две штуки на страницу. Эффективнее указать в тексте последовательность пунктов меню или кнопок. Можно с картинками кнопок, но непосредственно в тексте, а не на общем скриншоте всего окна, который занимает полстраницы. А инструкции, предназначенные для IT специалистов - администраторов, сервис-инженеров, сотрудников поддержки, вообще не должны содержать никаких скриншотов. Они должны быть максимально краткими, в идеале умещаться на одну страницу. Такую инструкцию скорее нужно называть памяткой. Предполагается, что специалист понимает смысл того, что делает, так как, если не понимает, то "медицина здесь бессильна"

Не нужно сбрасывать атомную бомбу на курятник, чтобы пожарить яичницу

Если Вы пишете софт для внутреннего использования в своей организации и являетесь единственным его разработчиком, у Вас, как правило, есть полная свобода в выборе используемых технологий. И Вы размышляете, на чём писать, на чём хранить данные. Конечно, если Вы собираетесь менять работу, то Вы заинтересованы в опыте применения наиболее модных в данный момент технологий. Но если не собираетесь, то следование мировым тенденциям, конъюнктуре на рынке труда и собственному желанию выглядеть невероятно крутым контрпродуктивно. Нужно исходить из особенностей задачи и имеющихся ресурсов. Мне довелось наблюдать душераздирающее зрелище - на очень слабую машину поставили Oracle, несчастный компьютер стал загружаться сорок минут. Зато Oracle! Нет никаких причин, кроме больного самолюбия, использовать платформы для крупных корпоративных решений там, где можно обойтись чем-то очень простым и не требующим огромных вычислительных мощностей. Может быть, Вам вообще не нужен SQL сервер, можно обойтись файловой СУБД. А может быть, вообще никакой СУБД не понадобится, всё можно хранить в текстовых файлах. То же самое относится к клиентскому программному обеспечению - например, если у будущих рабочих станций Вашей системы нет переизбытка памяти, следует забыть про Java - Delphi Ваше всё! К тому же, уже давно есть бесплатная лицензия. Да что там - огромный спектр задач решается с помощью Excel и VBA. И несмотря на то, что я этот VBA терпеть не могу, вынужден признать, что это очень часто вполне эффективно, хоть и совсем не круто. При выборе средств решения задачи нужно исходить из объективно существующих условий, а не пресс-релизов Microsoft, Google и Oracle.

Будьте проще

Больше двадцати лет назад, когда я только начинал работать программистом и почти не знал SQL, столкнулся с необходимостью найти и исправить ошибку в запросе, написанном до меня. Там, видимо, была ошибка где-то в условиях join или использовался необоснованно left join. Я этого никогда не узнаю, потому как, имея очень смутное представление о том, как работает join, я выкинул их все, переписал как понимаю. Получилось явное соединение таблиц с перечислением таблиц в from и условиями соединение в where. И всё заработало как надо. А теперь бывает, что ловлю себя на том, что описываю курсор, обобщенное табличное выражение, использую оконные функции и т. д. не потому, что это нужно, а потому, что умею. Особенно курсоров касается, от них один вред - очень сажают производительность. Зато выглядит круто! Нужно эффективно решать поставленную задачу, а не рисовать код неземной красоты.

В заключение повторюсь - не использовать для учёбы и корпоративного трудоустройства. Если Вы на экзамене скажете, что первичный ключ не нужен - будете пересдавать. А если в Microsoft узнают, что Вы задумали сложить в текстовые файлы то, что раньше лежало на MS SQL Server, Вам придётся перейти на нелегальное положение...

Комментарии (68)


  1. iiwabor
    27.10.2021 13:30
    +7

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


    1. MentalBlood
      27.10.2021 14:46
      +4

      Дык может новоприбывшие еще неопытны, мало кода читали, и им почти все сложно. Не только от кода зависит, так что не только он может быть злом


    1. thenikita
      27.10.2021 17:23
      +12

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

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


      1. GospodinKolhoznik
        27.10.2021 19:34
        +13

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


        1. gremsta
          29.10.2021 12:57

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

          Resume-driven development - как же без этого свое резюме делать привлекательным?


      1. chernish2
        27.10.2021 23:22
        +1

        По всем канонам-это как конкретно?


    1. GospodinKolhoznik
      27.10.2021 18:40
      +1

      It depends. Иногда важнее качество, скорость, надёжность.

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

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


    1. DarthVictor
      28.10.2021 12:09

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

      Это по-моему не зло, а оксюморон


  1. 0xlevi
    27.10.2021 14:22
    +3

    Хочется добавить сюда ещё бесконечные важные споры о том, что же использовать: табы, 2 пробела или 4; максимальное кол-во символов в строке или имени метода/класса, максимальная длина сообщения для коммита и прочие очень важные вещи для закрытой кодовой базы. (работал когда-то в комманде, где 2 лида и архитектор буквально 3 часа рабочего времени спорили по поводу длины названия метода)

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


    1. sergey-kuznetsov
      02.12.2021 02:29

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


      1. 0xlevi
        02.12.2021 13:00
        +1

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

        Между понятностью и религиозным ограничением на символы, я выберу первое. Считаю, что лучше превысить лимит на пару символов и написать понятно, чем сидеть и думать "как же это всё так перефразировать, чтобы не дай бог не превысить лимит" и в итоге написать так, чтобы для понимания, что же именно коммит изменил, нужно было идти в его детали.

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

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


        1. sergey-kuznetsov
          07.12.2021 03:32

          А вам не жаль того человека. который вынужден будет читать эту портянку, которую расколбасило при выводе git log или в интерфейсе GitHub? Ведь эти рекомендации не с потолка придуманы а являются следствием опыта старших товарищей.

          Делайте как угодно, я лишь попросил не путать понятия. Длину сообщения никто не ограничивает.


          1. 0xlevi
            07.12.2021 11:17

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

            Во-вторых, касательно git log - если разработчик использует консоль/терминал, где максимальная длина вывода 80 символов и он предпочитает страдать с переносами вместо того, чтобы что-то изменить, то да, мне таких людей жаль. Ведь дело не только в том, что на такой маленькой консоли неудобно читать git log - я бы сказал, что лог любой программы так читать неудобно.

            В-третьих, "эти рекомендации не с потолка придуманы" - да, не с потолка, а со времён, когда разрешение экрана измерялось в символах, а потом укрепилось во времена 640х480. Я не понимаю как в 2021 с нашими офигевшими технологиями, где 2к уже в мобилку пихают, а 4к в ноуты, можно вообще поднимать тему кол-ва символов в строке. Разве что, это единственная проблема на вашем проекте - в таком случае я по-доброму завидую вам.


  1. UScorp
    27.10.2021 14:27
    +7

    При этом никакого поиска по этой таблице не происходит, только вставка и обновление данных.

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

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


    1. censor2005
      27.10.2021 15:46
      -2

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

      Например, так:

      UPDATE settings SET value="true" WHERE key="debug"


      1. a1ebedew
        28.10.2021 00:54

        Поздравляю, вы изобрели NoSQL.


      1. pin2t
        28.10.2021 03:30
        +1

        Как вы думаете, что происходит когда вы пишете WHERE key="debug"?

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


        1. censor2005
          28.10.2021 04:38
          +1

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


          1. UScorp
            28.10.2021 06:48

            Представим у нас есть 3 записи с полями descr, amount, key:

            1) key=debug, amount=10, descr='колбаса'

            2) key=debug, amount=20, descr='колбаса'

            3) key=info, amount=25, descr='масло'

            Мне нужно обновить вторую запись, поменяв сумму с 20 на 30. Условия "WHERE key="debug"" будет явно недостаточно. И даже добавление условия "descr='колбаса'" тоже будет не достаточным. А если у нас есть 2 абсолютно одинаковые записи, например добавим 4-ю запись:

            4) key=debug, amount=20, descr='колбаса'

            А мне по прежнему нужно обновить вторую запись, при этом не затронув 4-ю. То я уже это просто не смогу сделать, т.к. нет критерия однозначного определения нужной записи.

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


            1. censor2005
              28.10.2021 07:00
              +2

              Зачем вы приводите надуманные, не существующие в реальности примеры? Естественно, что для подобной структуры необходим первичный ключ. Можно создать таблицу для хранения key-value значений, и первичный ключ тут не будет обязательным. Достаточно будет добавить индекс для быстрого поиска


              1. Rsa97
                28.10.2021 10:12
                +8

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


              1. UScorp
                28.10.2021 10:46

                Почему же такой пример не имеет право на жизнь?

                Представим, что это некий буффер продаж за день, где key - это продавец, descr - это товар, а amount - это цена, за которую он ее продал.

                За один день продавец debug продал 3 колбасы, но в какой-то момент вспомнил, что вторую колбасу он продал не за 20, а за 30 у.е. и захотел это исправить. Но при такой структуре у него это уже не получится сделать.

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

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


                1. ksbes
                  28.10.2021 11:46
                  +3

                  но в какой-то момент вспомнил, что вторую колбасу он продал не за 20, а за 30 у.е. и захотел это исправить. Но при такой структуре у него это уже не получится сделать.

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


                  1. mayorovp
                    28.10.2021 11:57

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


                    1. ksbes
                      28.10.2021 12:01

                      Не обязательно. И даже вредно - ролей-то у него может быть много => много строк в таблице прав.

                      Вообще реализовывать реляционные связи "через код" (i.e. слабое связывание) - это не плохая (и не хорошая) практика, а архитектурный выбор.


                      1. mayorovp
                        28.10.2021 12:31
                        +1

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


                      1. ksbes
                        28.10.2021 12:38
                        -2

                        Ну вас же: "специально уполномоченному человеку нужен будет уникальный идентификатор строки".

                        Уникальность как предполагали обеспечивать без внешней таблицы с уникальным ключём? Вот вам и таблица ролей с правами и реляционная связь. Так что минусик - возвращайте обратно :)


                      1. mayorovp
                        28.10.2021 13:00
                        +1

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


                      1. ksbes
                        28.10.2021 13:15

                        Э-э-э, а как внешняя таблица поможет вам обеспечить уникальный ключ для строки?

                        Foreign Key. Слышали о таком? Иначе у вас, где "key - это продавец <...> ваше key в данном случае и является первичным ключом" - этот продавец больше одного товара в день не продаст. Просто по определению ключа (он должен быть уникальным во всей таблице (по всем строкам))

                        И причём тут вообще таблица прав?

                        В простейшем наивном случае - именно там хранятся пользователи заодно с правами (на проводку той же коррекции)

                        Мы с вами явно друг друга не конца понимаем. Это не повод реагировать эмоционально. Это повод более чётко изложить свою позицию.


                      1. mayorovp
                        28.10.2021 18:16

                        Напоминаю задачу.


                        У вас есть таблица, с атрибутами key, amount и descr. Ни один атрибут не является уникальным, так же как и ни одна комбинация атрибутов. Вам нужно обновить одну из строк этой таблицы, так как она содержит ошибочные данные.


                        Как вам поможет в этой задаче внешний ключ на таблицу прав пользователей?


                      1. ksbes
                        28.10.2021 18:28

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

                        По сути:

                        С каких это пор в такой таблице разрешено вообще что-либо обновлять?

                        Просто добавляется транзакция:

                        • key=corrector, amount=10, descr='колбаса'

                        (или -10, если надо скорректировать в другую сторону,)

                        Для биг-даты и сведения балансов (а для чего ещё эта таблица сойдёт?) этого достаточно. Зато сразу понятно какая смена чаще косячет.


                      1. mayorovp
                        28.10.2021 18:33

                        Задумку понял. Но неужели вот прямо совсем-совсем никому не интересно какая именно запись была скорректирована? Не верю.


                      1. ksbes
                        28.10.2021 18:48

                        Как специалист сразу задам вопрос: а в каком бизнес-процессе вы эту информацию используете? Какое решение на её основе примите? Ни в каком? Никакое? (чаще всего так и есть: для продавца единицы товара как электроны - неразличимы) Тогда зачем тратить ресурсы (программистов и системы)!

                        Просто любопытство - не основание.

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


                      1. unsignedchar
                        28.10.2021 19:31

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


                      1. UScorp
                        29.10.2021 06:07
                        +1

                        С каких это пор в такой таблице разрешено вообще что-либо обновлять?

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

                        Но так ведь весь сыр-бор в этой ветке я начал с цитаты из статьи:

                        При этом никакого поиска по этой таблице не происходит, только вставка и обновление данных.

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


        1. UScorp
          28.10.2021 06:57
          +2

          На самом деле, наличие первичного ключа не есть наличие соответствующего индекса. Это зачастую зависит от реализации СУБД. Т.е. теоретически, ничто не мешает нам создать первичный ключ и не использовать соответствующий индекс.

          Просто, в таком случае, проверка уникальности первичного ключа и поиск по нему будет более трудозатратной для СУБД.


          1. unsignedchar
            28.10.2021 08:10

            Я думаю, что трудозатратностью поиска (а также созданием первичного ключа и индексов) в таблице с 10 строками можно пренебречь.


    1. mvv-rus
      28.10.2021 17:11

      Интересно, а как находить и обновлять нужную запись, если на ней нет первичного ключа?
      Насколько я понял автора, в его случае править в той таблице ничего не было нужно: она использовалась чисто как очередь сообщений, которые впоследствии асинхронно отправлялись на серевер.


  1. SadOcean
    27.10.2021 15:28
    +11

    Недооценённый совет про избегание дубляжей.

    Многие вдохновляются принципом DRY, и обобщают любой похожий код.

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

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

    Разделять такое сложно


    1. 0xlevi
      27.10.2021 16:20
      +8

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


    1. kellas
      27.10.2021 22:39
      +2

      Вот тоже не понимаю этой какой-то привычки чисто экономить место на диске )

      Тут важно понимать что дубликат_кода !== дубликат_функционала

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

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


    1. ksbes
      28.10.2021 10:41

      Поддерживаю.

      Как говорил один мой старший коллега - лишние стрелочки намного хуже лишнего кода.

      Т.е. DRY драем, но не в ущерб разделению ответственности и логическому делению кода.

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


  1. saboteur_kiev
    27.10.2021 17:37
    +6

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

    Преждевременная оптимизация тоже зло.

    Вдобавок зачем ссылаться много записей. Через 5 лет добавить отдельную таблицу, где будет множество строк с "user" - "department ". Но если это не нужно сейчас, то не нужно. Иначе можно к любой информации так относиться, и будет тысячи таблиц, которые может быть будут использованы через 5 лет, а может и нет.


    1. mSnus
      27.10.2021 20:25
      +5

      А тут никогда не угадаешь, если система не спроектирована жёстко заранее. DRY приводит к ошибкам вида god objects, не-DRY -- к ошибкам "в двух местах поменял, в третьем забыл". С таблицами та же фигня - то на каждый чих три таблицы вместо одной, то в одном поле хранится десяток значений в json или через запятую..


      1. saboteur_kiev
        28.10.2021 03:22

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


        1. Lexicon
          28.10.2021 09:05

          Гадать есть смысл пока "это условно можно переписать за человекогод".


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

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


          1. Survtur
            28.10.2021 12:21

            "schemaless" — блин, я как-то отвратительно это слово прочитал.


        1. mSnus
          28.10.2021 10:57

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


  1. ayevdoshenko
    27.10.2021 20:50

    Это называется KISS.


  1. unsignedchar
    27.10.2021 23:27
    +7

    Что для Вас хуже - наличие несвязанных записей в базе или непрерывные звонки от пользователей

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


  1. mvv-rus
    28.10.2021 05:00
    +5

    Внешние ключи — зло

    Это, пожалуй, единственное в тексте, с чем я не согласен категорически (остальное обсуждаемо).
    Точнее, я бы, может, и согласился, если бы это относилось исключительно к полям, по которым никто и никогда не будет искать.
    А вот для поиска и фильтрации нужно соблюдать порядок.
    Потому как в свое время (больше 20 лет назад), столкнулся с переносом данных о квартирах в фирме по торговле недвижимостью из плоской таблицы на Paradox в полноценую БД в почти что 3-й нормальной форме,, сделанную на полноценном SQL-сервере (Interbase).
    Основная причина нормализации была в том, чтобы по полям БД можно было бы эффективно искать и ставить на них фильтры.
    В процессе подготовки переноса данных (которым я, в основном тогда занимался) были обнаружены удивительные факты. Например, вариантов написания названия станции метро «Преображенская площадь» в базе было на момент переноса аж 22 штуки.
    А поскольку поиск по станции (или нескольким близлежащим станциям) метро был одним из востребованных запросов клиентов (в те времена запросы шли к девочкам на телефоне), то заставлять девочек ставить ради одной станции 22 галочки в фильтре выглядело как-то, даже не то, что негуманным, а просто снижающим производительность оператора, т.е. потерей денег.
    А без внешних ключей обеспечить консистентность справочников — оно никак.
    А потом у фирмы ещё и появился сайт, сделанный по последнему слову тогдашних технологий: динамический (на Perl через CGI), с фильтрацией информации по квартирам по параметрам согласно выбранных элементов справочников, и даже с картой метро (на Java applet), игравшей роль интерфейса для выбора этих самых станций метро из соответствующего справочника. Данные в БД сайта гнались практически напрямую из основной БД, и я даже не представляю, что было бы с посетителями сайта, если бы в ней по прежнему оставались 22 варинта названий станции метро.

    PS И ещё.
    можно обойтись файловой СУБД

    Файловая СУБД — палка о двух концах. С одной стороны просто, с другой — она может порушиться при зависании — нет, не сервера, а клиентского компьютера. И требовать восстановления в монопольном режиме. Когда пользователей немного, несколько человек — это терпимо, но когда базой пользуется вся фирма (как упомянутой базой квартир на Paradox) — то процесс ее восстановления требует проворства и сноровки.
    Я несколько раз наблюдал за слаженной работой специалистов по восстановлению этой базы в четыре руки: один за консолью Netware смотрел, когда отсоединятся все пользователи (и побуждал отсоединяться тех, кто не отсоединялся), а второй по сигналу первого захватывал базу в монопольный режим и запускал восстановление.
    Всегда приятно смотреть как люди работают.


    1. mSnus
      28.10.2021 11:04

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


      1. mvv-rus
        28.10.2021 17:08

        Собственно, БД, про которую я писал выше, была именно так и сделана: ссылки на справочники в основной таблице были суррогатными первичными ключами справочников. Но внешние ключи для этих ссылок были, естественно. Иначе, если не накладывать ограниечение внешнего ключа, то записи, ссылающиеся на отсутствующие элементы справочника, просто не попадут в выдачу запроса, если в нем не используется OUTER JOIN — а автор тут сам рассказывает, как он избавился от всех JOIN, потому что просто не умел в них (а, к примеру, для тогдашнего Interbase запрос с LEFT OUTER JOIN сильно портил производительность — оптимизатор Interbase не умел как следует работать с такими запросами — и такие запросы, там где они были реально нудны, лучше было вручную бить на два спомощью UNION).
        А если нагрузку на СУБД требуется снизить, то приходится в основной таблице хранить сами значения, чтобы запрос не лазил по справочникам. Правда лично я с такой нуждой сталкивался во времена, когда БД писали на Clipper, но тем не менее.


        1. mSnus
          28.10.2021 17:39

          Всё так, но внешние ключи имеют свои недостатки, не только преимущества.

          Навскидку -- их использование предполагает, что записи удаляются, а не "помечаются как удалённые", и если БД уже спроектирована с ними, то на уровне простого разработчика это будет уже неисправимо.

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

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


  1. Yser
    28.10.2021 05:51
    +6

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

    При выборе средств решения задачи нужно исходить из объективно существующих условий

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

    Итого мы имеем:

    Базу на файлах или базу без даже первичных ключей - потому что мы исходим из текущих требований.

    С кучей ассоциативных таблиц - потому что many-to-many и вы все в мыслях о будушем.

    И код наш продублирован везде где только можно и нельзя - потому что, а вдруг придется его менять, а тут раз, взял и добавил то что надо в 37 мест из 52.

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


    1. zetroot
      28.10.2021 09:05
      +3

      Job security же!

      И мысли ”о будущем" - какие то не те. Смигрировать связь one2many в many2many дело совсем не сложное для более менее опытного разработчика, а вот не умереть пытаясь вникнуть во все эти "заделы на будущее" - вот где испытание. Возможно сделанное специально, но неосознанно.


  1. eugeneyp
    28.10.2021 10:22
    +2

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

    Иногда странно смотреть когда добавляют синтетический ключ для вспомогательной таблицы при описании отношений N:M. Но при этом первичный ключ там нужен на паре FK.

    Также есть конструкции SQL как ON UPDATE CASCADE / ON DELETE CASCADE они помогают изменять и удалять записи при наличии FK. Или можно использовать ON DELETE SET NULL.

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


  1. Virgo_Style
    28.10.2021 11:10

    Если нет полной уверенности, что отношения «один-много» будет достаточно для любого случая, лучше делать «много-много» через промежуточную таблицу. На всякий случай.

    Дело пахнет связкой один ко многим и таблицей истории изменений, по которой а) можно будет строить исторические отчеты б) ловить за руку «я ничего не делала, это у вас программа неправильно работает». Для чего в таблице должны быть оба id, дата-время изменения и какой-то user_id (username, role, что-то свое — по вкусу).


  1. namikiri
    28.10.2021 11:13

    Не нужно сбрасывать атомную бомбу на курятник, чтобы пожарить яичницу

    Доля правды в этом «вредном» совете есть. Нынче модны-популярны всякие браузеры, которые ну очень активно косят под нативные приложения. Да, Electron и иже с ним. Вот их, пожалуйста, не надо использовать. Особенно в софте, который разрабатывается для десктопа и планируется к публикации в открытом доступе. Teams, Slack и прочие — отличный пример того, как делать не надо. Просто попробуйте поменять размер окна и вы всё поймёте. Discord — хороший пример, но шанс на то, что вы сделаете так же, стремится к нулю.


  1. wkia
    28.10.2021 11:51
    +2

    Хоть название статьи и не предполагает серьезного отношения, но всё же.

    Лишняя таблица не лишняя

    https://ru.wikipedia.org/wiki/YAGNI

    Лишний код не лишний

    https://refactoring.guru/ru/refactoring/smells/change-preventers

    Инструкция не комикс

    Это, конечно, да. Но сможете ли вы на одной странице "памятки" понятно описать правила работы с вашей программой? Особенно это касается программ для внутреннего использования, при разработке которых обычно фокусируются на функционале, а не на UI. Классика: «Программисты (...) много работают, чтобы сделать свои программы легкими в использовании. К сожалению, судят они по себе...» А.Купер.

    Будьте проще

    Этот очень хороший пункт противоречит многим местам в вашей же статье.


  1. vdasus
    28.10.2021 15:34
    +4

    Из моего богатого опыта — за «Даже первичный ключ необязателен» я готов убивать…


    1. mvv-rus
      28.10.2021 16:54

      Дык, автор-то, как я понял, описывает случай, где и таблица-то не нужна, и СУБД — тоже: ему там просто нужна очередь, куда скидываются оперативные записи об изменениях, впоследствии асинхронно отправляемые в хранилище. Вообще-то, полноценно подобные задачи реализуются совсем другим классом систем, не СУБД — очередями сообщений. В Windows одно время система такого класса — MSMQ — была практически встроенной, но за пределами кровавых энтерпрайзов ей AFAIK все равно мало кто пользовался. Ну, а в маленькой системке для небольшой фирмы вполне мог использоваться вместо этого свой велосипед на СУБД с таблицей без первичного ключа — если порядок отправки сообщений не важен.


  1. pavelsc
    28.10.2021 15:44

    После универа поработал "карманным" программистом в ООО на 20 человек. К сожалению если не работать на работе и после работы на фрилансе, то даже через 20 лет не дотянешь до мидла галеры в СНГ. Бесконечные лендинги и дотнет тулзы по тз "нужны кнопка которая нажимала бы три для манагера" оставляют скилл на уровне стажера.


    1. Bandicoot
      29.10.2021 00:16

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

      Искренне не понимаю ребят, работающие в аутсорсе, на галерах. Нужно такое счастье…


  1. z0ic
    28.10.2021 16:50
    +2

    Если в полночь на экране появился Segmentation Fault.

    Ты не бойся, первым делом сделай из осины кол.

    Забивать его не надо, в злых поступках мало толку.

    Этой палкой надо просто нацарапать надпись LOL.


  1. HemulGM
    06.11.2021 23:29
    -1

    Где вы в последний раз видели рекомендацию использовать Delphi? Здесь это упоминание не уместно и выглядит не более чем негативное отношение к языку.

    В современных реалиях логично было написать: "следует забыть про Java - Python Ваше всё!". Это недоразумение сейчас из каждого угла лезет.


  1. vladvul
    10.11.2021 10:08
    -1

    KISS бьёт DRY


  1. sergey-kuznetsov
    03.12.2021 06:26

    Читаю статью и не могу понять в чём подвох. Обещали вредные советы, но все утверждения выглядят очень даже дельными.