zHz00 Untitled

среда, 15 февраля 2017
23:58 Что посеешь, то и пожмёшь
Одним проектом я не занимался год. Потом открыл. Ох, как всё запущенно.

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

1. У переменных должны быть понятные имена. Это касается не только переменных типа _, asdbsd и Burrrrp (хотя игроку в НетХак последняя будет весьма понятна) -- тут всё ясно. Название может иметь отношение к реальной ситуации, но имеет шанс быть воспринятым неправильно. Так, у меня в программе была переменная по имени need_count. Я долго думал, что это число раз, которые надо (need) посчитать (count) что-то. Однако на самом деле эта переменна обозначало то, НАДО считать (1) или НЕ НАДО (0).

2. Отсюда вытекает второе правило -- тип переменной должен соответствовать её назначению. Переменная из п.1 имела тип int. Хотя гораздо понятнее всё было бы, если бы я сделал её типа _Bool (это было в той части проекта, которая работала на микроконтроллере, а она написана на голом Си-99, поэтому именно _Bool, а не bool). Для МК, это, правда, простительно, т.к. int будет быстрее обрабатываться в ряде случаев.
Примечание. Беззнаковые типы при совместном использовании со знаковыми таят в себе гремучую бомбу: zhz00.diary.ru/p211118163.htm

3. А третье правило -- не следует повторно использовать ту же переменную для других целей. Хотя для переменных типа x, y, i особой разницы нету, сколько раз их использовать. Но повторное использование более специальных переменных часто ведёт к нарушению п.1. То, на чём конкретно напоролся я -- WriteFile возвращает через указатель число записанных байтов. Для этого я использовал переменную с подходящим именем written. Но потом мне надо было читать данные при помощи ReadFile. Как не трудно догадаться, он тоже через указатель возвращает число байтов, но уже прочтённых. Видимо тогда я решил сэкономить четыре байта. Ну вот нафига? Да-да, именно так. Я написал --

ReadFile(hFile,size,&written,NULL);

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

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

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

@темы: Программирование, Говнокод, Очевидное-невероятное

URL
Картинку в нете нашел :))
http://www.haroldsplanet.co.uk/
Самое любопытное: страусиное наше сознание, оказывается, ...
Ночь жизни. Ты уже привык терять. Ты несешься вперед, ст...
дожил начал пить чай
Подруга не звонила месяц. А я забыла поздравить ее с днем...

16.02.2017 в 11:16

16.02.2017 в 11:16
Если Вы смотрите на то, что написали 5 лет назад и считаете это полным дерьмом, то всё не так уж плохо.

Всё по-настоящему плохо, когда Вы смотрите на то, что написали 5 лет назад и считаете это гениальным.
URL

16.02.2017 в 12:30

16.02.2017 в 12:30
Knows Ajed, гениальными я обычно считаю свои старые посты на дайари. Не все, но некоторые. Хотя то, что я писал 5 лет наза,д мне нравится меньше, чем то, что я писал 3 года назад. А вот дальше улучшений что-то нет -- в смысле, круче уже некуда.
URL

16.02.2017 в 16:43

16.02.2017 в 16:43
тернарный оператор я нежно люблю, но во избежание граблей мы договорились, что нельзя вызывать мутирующие функции в ветвях.
URL

16.02.2017 в 17:51

16.02.2017 в 17:51
korrshun, что такое мутирующие функции и какое они имеют отношение к достопочтенному тернарному оператору?
URL

16.02.2017 в 18:14

16.02.2017 в 18:14
Это типа x=(y>0?sin:cos)(t); ?
URL

16.02.2017 в 18:36

16.02.2017 в 18:36
В случае с js это несёт ещё одну важную гигиеническую цель - чистые функции обычно синхронные (получают и возвращают значение, а не Promise или не ожидают на вход каких-то callcack), и не требуют особых приседаний в виде написания доп. кода, который обработает ошибки, вылетевшие из них.

Примеры пусть и на js, но достаточно поясняют идею.

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

result = x ? response.send(JSON.stringify(x)) : response.sendStatus(404)

А вот так, писать можно:

style = foo ? calcStyle(foo) : getDefaultStyle()

потому что эти функции чистые и не меняют мир вокруг.
URL

16.02.2017 в 19:03

16.02.2017 в 19:03
А, мутирующие функции -- это НЕ ЧИСТЫЕ.
URL

16.02.2017 в 21:12

16.02.2017 в 21:12
Отсюда вытекает второе правило -- тип переменной должен соответствовать её назначению.
Есть даже более жёсткое правило, которое на мой взгляд удобно: тип переменной должен *точно* определять, что в ней хранится.
Иными словами, переменные типа инт годятся только для счётчиков, но не для длины (для неё нужен typedef int pixelWidth), ширины, а тем более переменных, которые используют его хитро, например, децибелл, записанных в десятых долях (215 = 21.5 Дб).

Это не только делает код читаемым (pixelWidth width, decidB db), облегчает проверку типов (если ты присваиваешь dB к width, ты действуешь неправильно), мало того, это определяет конкретное место, где описано, что хранится в типе. А именно, там, где тип определён. Там ты даёшь все комментарии о том, как он устроен. Из любого места, где тип используется, ты можешь туда перейти одним щелчком.

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

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

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

16.02.2017 в 21:22

16.02.2017 в 21:22
himself, идея классная, но свободолюбивый я возражает. Надо это в Rust ввести. Там много подобных эмм... "ограничителей".
URL

16.02.2017 в 21:36

16.02.2017 в 21:36
zHz00, она как раз... освобождает :)
Как и большинство хороших правил, её необязательно применять везде, можно только там, где хочется. Но со временем, когда к ней привыкаешь, то начинает хотеться так делать. Когда собираешься объявить нетривиальное поле, тут же в голове всплывают гадости: многократная документация где попало, неуверенность, где же формат документирован и документирован ли вообще; путаница, отладка из-за того, что кто-то не понял. И тут же хочется вот взять и объявить аккуратненько так :)
URL

16.02.2017 в 22:03

16.02.2017 в 22:03
himself,
>> она как раз... освобождает :) <...> Но со временем, когда к ней привыкаешь, то начинает хотеться так делать.

Прям как сегодняшний пост Эволюции про нравственность.
URL

17.02.2017 в 13:20

17.02.2017 в 13:20
Надо это в Rust ввести

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

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

а давайте тогда сразу haskell!
Есть там одна фиговина по имени Ivory - с её помощью можно потом сишечку генерить из хаскелля, чтобы типобезопасно и красиво.
URL

20.02.2017 в 10:34

20.02.2017 в 10:34
Я безнадёжно испорченный человек. Из-за парадокса Блаба, для меня
("Haskell" == "Brainfuck") == true
URL

20.02.2017 в 12:47

20.02.2017 в 12:47
Ух ты, какая штука. Про парадокс Блаба не слышал!

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

20.02.2017 в 15:39

20.02.2017 в 15:39
zHz00, да, по сути, тот же парадокс Блаба. ) Плюс-минус. )
URL
Добавить комментарий

Расширенная форма

Подписаться на новые комментарии
Получать уведомления о новых комментариях на E-mail