Pull to refresh
56
0
Сергей Садовников @FlexFerrum

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

Send message
Да его много для чего юзать можно.
> Все эти методики работают только при определенных навыках работы с кодом. Я и в сложных проектах вижу только такой путь — чем проще тем лучше. Не могу себе представить, где это не работает.

Собственно, дополняя этот тезис, хочу сказать, что не только при определённых навыках, но и просто не во всех ситуациях. Факторов, на самом деле, много (характер задачи, размер команды, опыт членов команды, перспективы задачи и т. д. и т. п.), и то, что прекрасно работает при одной комбинации этих факторов, перестанет работать при другой. А так… Безусловно — у каждого свой опыт. Мне приходилось работать и в ситуациях, когда постоянный рефакторинг был возможен (и оптимален), а также в ситуациях, когда принятые «сейчас» решения уже нельзя было отменить, или это было ну ооооооочень дорого.
На самом деле всё просто. :) Всё сводится к оценке рисков и вероятностей. Понятно, что для проектов «сделал и забыл» подходит принцип «Чем проще, тем лучше». Для проектов, которые предполагают длительный период развития, несколько релизов и т. п. — уже нет. Очевидно, что если переписывание кода «потом» будет менее затратно, чем сделать прослойку «сейчас» — то и вопросов нет. Код as simple as possible + тесты. Если же будущий рефакторинг может быть более затратный — то риски просто необходимо оценивать, исходя из текущей ситуации и предположений. И уже по результатам таких оценок принимать решения. И универсальных рецептов тут нет.

Про БД — пример то прост. Ну, например, «сейчас» код пишется с использованием прямых SQL-запросов к базе. Положим, MySQL. А то и SQLite. Прошло некоторое время, нагрузка выросла, выбранная БД не справляется. Что делать? Переписать весь код, который завязан на работу с БД. А это чуть меньше, чем вся бизнес-логика. Это большой рефакторинг или маленький? Было бы лучше, если бы сразу было принято решение использовать какой-нибудь ORM?
А по мне, так не всё так просто. Одно дело, когда речь идёт про то, как раскроить иерархию классов, да распихать методы по интерфейсам. Другое — когда принимаются те или иные ключевые архитектурные решения, изменения которых аффектят 90% написанного кода. Ну, например, на начальном этапе принимается решение использовать некое средство X (например, средство доступа к БД). На этот средство завязывается весь код. А потом выясняется, что полученный продукт должен работать на порядок быстрее, и это самое средство X является бутылочным горлышком. Итоговый рефакторинг — это переписывание большей части кода (по сути — всё пишем заново). Но можно было бы поступить и иначе — для средства X написать фасад, и использовать только его. И потом (когда возникнет неприятность с производительностью) — только его и переписать. По-моему, затраты несопоставимые.
Вы привели неудачный пример с кружкой. Очевидно, что «кружка» — это пассивный объект из нашего окружения. А вот электрочайник — уже активный. Он может «кипятить воду», если его «попросить» об этом. И как представить операцию «кипятить воду» отдельно от объекта «чайник» в данном случае?

Дело в том, что ООП — это просто один из способов декомпозиции задачи для того, чтобы её можно было решить. Задачу можно декомпозировать по-разному. Более того, разные части задачи можно декомпозировать с помощью разных подходов. По этому говорить, что один подход принципиально лучше другого — это ошибка. Так можно утверждать только в контексте конкретной задачи. Понятно, что ООП — это не серебряная пуля. Просто потому, что серебряных пуль не бывает. И странно, что автор оригинальной статьи (с 17-летним опытом!) этого ещё не понял. Или сделал вид, что не понял. :)

gcc и clang поддерживают constexpr'ы. По этому большой необходимости в трюках с __forceinline и их аналогами нет.
Собственно, на constexpr'ах это волшебство будет выглядеть так:
constexpr uint32_t CalcCRC32Impl(uint32_t prevCrc, const char* str)
{
    return !(*str) ? prevCrc : CalcCRC32Impl((prevCrc >> 8) ^ Crc32Table[(prevCrc ^ *str) & 0xff], str + 1);
}

constexpr unsigned int CalcCRC32(const char* str)
{
    return CalcCRC32Impl(0xffffffff, str) ^ 0xffffffff;
}

Проверка:

template<int crc>
void PrintCrc()
{
    std::cout << crc << std::endl;
}

PrintCrc<CalcCRC32("123")>();


Печатает ожидаемое 884863d2.

Проверял на gcc 4.7. Таблица Crc32Table такая же, как в статье.
Ну, я бы не стал настолько драматизировать. :)
По прочтению почему-то вспомнился «Младший Брат» Кори Доктороу. Там в деталях расписано, как ммм… продвинутая молодёжь направо и налево пользовалась описанной здесь технологией.
Eike Ziller писал по поводу интеграции QtC и clang буквально следующее:

1) First priority short term is to make Qt Creator's current code model handle the new C++11 features gracefully (help needed, see long story!)
2) Middle term (i.e. 2012/13) we want a hybrid solution where clang is used for code completion and semantic highlighting, and the current code model is used for mostly everything else
3) Long term we would prefer using clang for everything code related in Qt Creator, but when both clang and Qt Creator might be ready for that, we don't know


( lists.qt-project.org/pipermail/qt-creator/2012-February/000251.html )

Сейчас работа в рамках интеграции clang и QtC, судя по всему, временно заморожена. В master-ветке активно докручивается препроцессор. Когда работы с clang'ом возобновятся — я не знаю. У нокиевской команды, работающей над QtC, всего три человека (насколько я могу судить), которые работают над C++-парсером в QtC. По этому без помощи community им (для решения этих задач) никак не обойтись.
Да, с clang'ом там всё не просто (точнее, именно с его производительностью). Чем сложнее файл и больше в нём инклюдов — тем он дольше парсится. И это аффектит не только code completion, но и построение модели кода для проекта. Плюс ко всему, при сращивании QtC с clang'ом последнего надо «обучать» специфичным именно для Qt фишкам. Если с марта этого года ничего не изменилось, то QtC будет постепенно переводить на clang в течении 2012-2013-ых годов.
Вот, собственно, пример кода, когда автокомплит в QtC не может ничего предложить:
class SomeClass
{
public:
    SomeClass(int a) : m_a(a) {}

    void Foo() {}
    void Bar(int a) {}
};

int main()
{
    std::vector<SomeClass> vec;
    
    vec.front(). 

Тут после front() ничего не появляется при наборе. Аналогично с итераторами std-шных контейнеров.
В сложных случаях автокомплит в QtC в принципе тупит. Автокомплит auto будет работать во всех ситуациях, когда парсер QtC может вычислить тип выражения, а сюда не попадают даже достаточно простые случаи использования шаблонов, когда, например, парсеру надо пройти через несколько typedef'ов, особенно если они зависят от аргументов шаблона. Конкретные примеры кода смогу привести, когда до стационарного компа доберусь.

У этой проблемы два пути решения — докручивать встроенный парсер или окончательно переходить на clang, но на каждом из этих путей свои сложности.
Ну, по крайней мере пример, описанный в этой таске, работает:
image
Особенность работы всего это в том, что в QtC модель кода, извлечение семантической информации из исходника и т. п. действия выполняются асинхронно (в некоторых случаях — по таймеру). По этому временные лаги вполне возможны.
А может быть не стоит? В чём профит?
Да я и не говорил, что исключений не бывает. :)
Ну, собственно, если для адекватного понимания конструкции в продакшен-коде требуется хорошенько покопаться в стандарте (или использование этой конструкции ведёт к UB/ID), то лучше такую конструкцию не использовать.
Выше писали про SunCC (SunCC 5.5, если быть совсем точным) :)

Information

Rating
Does not participate
Location
Москва и Московская обл., Россия
Date of birth
Registered
Activity