Так себе программист
88 subscribers
90 photos
1 video
1 file
127 links
Давай созидать. Разработчик, преподаватель, к.т.н о программировании и профессии.

Пишу desktop на C/С++, а когда никто не видит, то еще что-нибудь на python и js :)

Большие статьи тут: https://atrotsenko.hashnode.dev

Автор: Александр Троценко
Download Telegram
Нужно ли рисовать указатели и ссылки в UML?

Нет, не нужно.

UML (Unified Modeling Language) - это язык моделирования. С его помощью создается модель, схема, проект, но никак не реализация.

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

В C++ такими деталями могут быть:
- указатели,
- ссылки,
- ключевые слова const, override, explicit ...,
- специфика стандартной библиотеки и т.п.

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

Но, честно говоря, я нет-нет да и влеплю бывает какую-нибудь закорючку & на схему 😁 Привычка, чтоб её...



Работаете с UML?

🔥 - ага
👍 - нет, я код пишу
🤷‍♂️ - эээ, ничего не понятно, но очень интересно
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6🤷‍♂1
Сегодня у нас тест по истории!

Целых 4 вопроса подряд ⤵️
В каком году появился язык C++?
Anonymous Quiz
0%
1943
21%
1963
79%
1983
0%
2003
В каком году появился язык Python?
Anonymous Quiz
0%
1968
9%
1985
57%
1991
35%
2009
В каком году появился язык Java?
Anonymous Quiz
13%
1975
87%
1995
0%
2005
0%
2015
В каком году появился язык Go?
Anonymous Quiz
0%
1989
18%
1997
73%
2009
9%
2019
🔼 Разнёс варианты ответов как можно дальше во времени, чтобы легче было отвечать навскидку.

Как справились?

🔥 - 100% успех
👍 - частичный успех
🤷‍♂️ - всё мимо
👍8🔥4
Нужно ли указывать virtual для переопределенного метода в C++?

Не нужно.

Сейчас объясню.

Иногда встречаю код по такому шаблону:

class Base 
{
public:
virtual void func() { /* ... */ }
};

class Derived : public Base
{
public:
virtual void func() override { /* ... */ }
};


🔼 Здесь в классе-наследнике Derived у переопределенного метода func() повторно указан virtual.

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

Когда-то давным-давно, когда в стандарте не было override, повторное указание virtual было оправдано. Просто так легче читать. Сразу видно, что метод виртуальный.

С появлением override необходимость в этом отпала. Слово virtual нужно указывать один раз в базовом классе метода. Вот так ⤵️

class Base 
{
public:
virtual void func() { /* ... */ }
};

class Derived : public Base
{
public:
void func() override { /* ... */ }
};




Мало C++? Тогда можно вспомнить про литералы
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
#include <iostream>

int main()
{
auto position = [](int w) {
return std::tuple(1 * w, 2 * w);
};

auto [x, y] = position(1);
std::cout << "(" << x << ", " << y << ") ";
std::tie(x, y) = position(2);
std::cout << "(" << x << ", " << y << ")";
return 0;
}
Выше дан код C++. Какой вывод будет у программы?
Anonymous Quiz
18%
(1, 1) (2, 2)
71%
(1, 2) (2, 4)
12%
(1, 2) (3, 4)
0%
(1, 2) (3, 6)
Все боятся, что джун положит прод...

🤔 Но почему никто не боится, что прод положит джуна?
😁4
Синтаксис или семантика

Синтаксис — это правила языка, его орфография.

Семантика — это смысл кода, его логика.

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

Оба термина можно встретить в контексте статического анализа кода. Анализаторы, благодаря строгим правилам языка, легко находят синтаксические ошибки. Сематические ошибки найти сложнее. Например, здесь в C++:

if ( x = 5 )
// ...


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



Ранее в сериале #Словарь 👉 Эмулятор или симулятор
👍2
Почему в CLI есть короткие и длинные ключи

При работе с командной строкой вы наверняка замечали, что у многих опций есть два формата:
- Короткий (например, -h)
- Длинный (например, --help)

🔸 Зачем это нужно?

Очевидно, что короткие ключи (-h, -v) обеспечивают быстрый ввод. При частом использовании самое то.

Длинные ключи (--help, --version) уже быстро не введешь, но они более понятные и читаемые.

Пример:
# Короткая запись
ls -l

# Длинная запись
ls --format=long


🔸 Тогда какой вариант использовать?

Короткие ключи используем при непосредственной работе с командной строкой. Здесь важна скорость и удобство.

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



В тему CLI еще можно вспомнить про путаницу в командах git.
3
А Филосо́ф - Без огурцов

У Крылова есть басня "Философ и огородник", где мужик-огородник сажает огурцы, а философ-огородник над ним смеется, мол, не по науке всё. Но пока философ читает книжки, думает, прикидывает и вымеряет, огородник - работает на земле. В итоге "у огородника взошло всё и поспело", "а философ - без огурцов".

🔽

Не знаю как вы, но я постоянно балансирую между "философом" и "огородником". Хочется посидеть, подумать как лучше, чтобы раз - и готово. Но опыт говорит: "Делай!"

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

Конечно, "философ" и "огородник" - это крайности. А в нашем интеллектуальном труде нужен баланс.

💡 Зная о своей склонности пофилософствовать, я стараюсь балансировать, придерживаясь цикла: "подумал - сделал - оценил". И чем короче цикл, тем лучше.

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

Поэтому когда в очередной раз повиснете в мыслях над своей лучшей задачей, вспомните про "филосо́фа - без огурцов" и спокойно переходите к делу 😉



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

#КнижнаяПолка
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
Исходный код:
#include <iostream>
#include <string>

int main(int argc, char* argv[])
{
std::string words[argc];
for (int i = 1; i < argc; ++i)
words[i - 1] = std::string(argv[i]);
for (int i = 0; i < (argc - 1); ++i)
std::cout << words[i] << " ";
return 0;
}

Аргументы командной строки:
hello world
Выше дан код C++. Какой вывод будет у программы?
Anonymous Quiz
39%
hello world
0%
world
11%
hello
50%
Зависит от реализации компилятора
Почему я не люблю auto в C++

Когда мы переходили на стандарт C++11, я еще тогда воротил нос от auto. Было не понятно, зачем он мне. Какой смысл?

C++ — язык со статической типизацией. Это значит, что типы известны на этапе компиляции, и это даёт предсказуемость и удобство чтения.

Ну например. В этом коде понятно, что мы имеем дело с вектором целых чисел:
std::vector<int> numbers = {1, 2, 3};


А здесь у нас что? vector, list, initializer_list или еще чего-нибудь?
auto numbers = {1, 2, 3};


🔸 Можете, конечно, возразить: "Есть ситуации, где тип реально не важен".
И я вам скажу: "Да, есть. Когда вы только-только пишете код". Но когда вы будете его читать через лет, эдак, полгода, то на момент зависните, пытаясь в уме разыменовать этот auto.

Да что в уме? Даже среда разработки иной раз не может подсветить методы у объекта, так как не соображает, что там за тип внутри)

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

🔸 Вы снова возразите: "А как же сложные типы? Шаблоны и прочие бутерброды".
И я вам скажу: "Вы снова правы". Ну очень не хочется писать этот длиннющий std::unordered_map<MySpace::MyType>::iterator. Набрал auto и все дела. Я и сам так делаю. Но потом, перед коммитом, скорее всего заменю auto если не на оригинальный тип, то на какой-нибудь более осмысленный алиас. Если, конечно, не забуду 🤭

Как видите, лично у меня auto не прижился. С ним так много вопросов и так мало ответов.

А у вас какие с auto отношения? Дружите?

👍 - дружу
🔥 - скорее так, знакомые
😁 - ох уж этот ваш C++
👍3😁2🔥1
#include <iostream>
#include <vector>

int main()
{
std::vector<int> a = {1, 2, 4, 5, 7, 8, 9, 10};

for (int i = 0; i < a.size(); ++i) {
if (a[i] % 2 == 0) {
a.erase(a.begin() + i);
}
}

for (int i = 0; i < a.size(); ++i) {
std::cout << a[i] << " ";
}

return 0;
}
Выше дан код C++. Какой вывод будет у программы?
Anonymous Quiz
28%
1 4 5 7 9
33%
1 5 7 9
17%
1 4 7 9
22%
Неопределенное поведение
Как не утонуть в правках. Git-стратегия для сложных задач с риском откатов

Ситуация: пилите большую фичу, написали много кода и вдруг замечаете, что сломали то, что час назад работало. Что случилось, почему? Открываете git diff, а там правки не за последний час, а за последний день... Где была допущена ошибка? Начинаем вспоминать, запускаем отладчик и забываем про текущую работу.

🔸 Как не доводить до такой ситуации?

Правильно - чаще коммитить. Но как коммитить то, что еще не готово? Коммит же должен быть завершенным!

Решение есть у нас: промежуточные коммиты.
Мы просто коммитим все, что хотим и когда хотим, а по окончании работ "схлопываем" промежуточные коммиты в один, используя interactive rebase.

Промежуточные коммиты оформляются с префиксом WIP (от Work In Progress), чтобы потом их не пропустить. В git log получается примерно так:
WIP: что-то сделал
WIP: еще что-то сделал
WIP: убрал кое-чего
WIP: зарефакторил то-то


🔸 Когда делать промежуточный коммит?

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

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

А чтобы вам проще было разобраться с подходом, я записал небольшое практическое видео. На простом примере показал как промежуточные коммиты помогают локализовать ошибку и как потом "схлопнуть" эти коммиты в один через interactive rebase. Ссылки здесь ⤵️

📱 Смотреть на YouTube

📱 Смотреть во ВКонтакте

#Troubleshooting
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1