Refactoring bezeichnet den Prozess, ein Softwaresystem so zu verändern, dass sich das von außen beobachtbare Verhalten des Codes nicht ändert, seine interne Struktur jedoch verbessert wird.
Bei der Organisation von Code-Refactoring lassen sich typischerweise drei Vorgehensweisen unterscheiden:
- Iteratives Refactoring: Eine Anwendung lässt sich nicht bereits in der ersten Iteration perfekt entwickeln – selbst mit den besten Architekten, Designern und Entwicklern. Ein pragmatischer Ansatz besteht darin, Refactoring in den Entwicklungsprozess zu integrieren und nach jeder Iteration durchzuführen, ohne dafür unverhältnismäßig viel Geld oder Zeit aufzuwenden. Iterative refactoring
- Refactoring bei Bedarf: Nach der Bereitstellung einer Anwendung werden häufig Fehler gemeldet. Wenn deren Behebung sehr zeitaufwendig ist oder sich neue Kundenanforderungen nur schwer in das bestehende System integrieren lassen, kann Refactoring eine gute Möglichkeit sein, die Qualität der Codebasis zu verbessern. In diesem Stadium kann es jedoch riskant sein; Regressionen im bestehenden Code müssen sorgfältig vermieden werden. Refactoring when necessary
- Kein Refactoring: Manchmal wird trotz zahlreicher Probleme in einer bestehenden Anwendung überhaupt kein Refactoring durchgeführt, weil das Management nicht in diesen Prozess investieren möchte. Das Support-Team muss dann mit dem durch Fehler und Rückmeldungen verursachten Aufwand und Stress umgehen. No refactoring
Wenn Ihr Team seine C++-Projekte regelmäßig refaktoriert und neue C++11-/C++14-Features einsetzen möchte, lohnt sich ein Blick darauf, wie bekannte C++-Projekte ihren Code für die neuen Standards modernisiert haben.
Der Chrome-Browser ist dafür ein gutes Beispiel: Seine Codebasis wird regelmäßig refaktoriert. Sobald neue Standards verabschiedet und von den Compilern unterstützt wurden, entschied sich das Chrome-Entwicklungsteam dafür, diese Standards einzusetzen.
Chrome ist ein ausgereiftes C++-Projekt. Daher ist es besonders interessant zu untersuchen, wie der Code implementiert und strukturiert ist. Schließlich wird Chrome von Millionen Menschen genutzt, was vom Entwicklungsteam entsprechend effizienten Code verlangt.
Wenn Sie Ihre C++-Codebasis refaktorieren möchten, um Features neuer Standards zu nutzen, lohnt sich ein Blick auf dieses interessante Google-Dokument. Es listet sowohl die erlaubten als auch die verbotenen C++11-/C++14-Features auf. Google document
Besonders interessant ist die Liste der verbotenen Features einschließlich der jeweiligen Begründungen. Es lohnt sich zu prüfen, ob diese Argumente auch auf Ihre eigenen Projekte zutreffen.
Hier sind die im Dokument aufgeführten verbotenen C++11-/C++14-Features:
Verbotene C++11-Features
| Feature or Library | Snippet | Description | Documentation Link | Notes and Discussion Thread |
|---|---|---|---|---|
| Inline Namespaces | inline namespace foo { ... } |
Allows better versioning of namespaces | Inline namespaces | Banned in the Google Style Guide. Unclear how it will work with components. |
long long Type |
long long var = value; |
An integer of at least 64 bits | Fundamental types | Use a stdint.h type if you need a 64bit number. Discussion thread |
| Ref-qualified Member Functions | class T {
void f() & {}
void f() && {}
};
t.f(); // first
T().f(); // second
std::move(t).f(); // second |
Allows class member functions to only bind to |this| as an rvalue or lvalue. | const-, volatile-, and ref-qualified member functions | Banned in the Google Style Guide. May only be used in Chromium with explicit approval from styleguide/c++/OWNERS. Discussion Thread |
| User-Defined Literals | type var = literal_value_type |
Allows user-defined literal expressions | User-defined literals | Banned in the Google Style Guide. |
| thread_local storage class | thread_local int foo = 1; |
Puts variables into thread local storage. | Storage duration | Some surprising effects on Mac (discussion, fork). Use SequenceLocalStorageSlot for sequence support, and ThreadLocal/ThreadLocalStorageotherwise. |
Verbotene C++14-Features
| Feature | Snippet | Description | Documentation Link | Notes and Discussion Thread |
|---|---|---|---|---|
| Function return type deduction | auto f() { return 42; }
decltype(auto) g() { return 42; } |
Ermöglicht es, den Rückgabetyp einer Funktion automatisch aus ihren return-Anweisungen abzuleiten, entsprechend entweder Template- oder decltype rules. |
Return type deduction | Temporarily banned since it can cause infinite loops in clang. Wir gehen davon aus, dies zuzulassen, sobald dieser Fehler behoben ist. Die Verwendung sollte selten sein und sich hauptsächlich auf abstrakten Template-Code beschränken. Discussion thread |
| Generic lambdas | [](const auto& x) { ... } |
Allows lambda argument types to be deduced using auto (according to the rules that apply to templates). |
lambda expressions | Temporarily banned since it can cause infinite loops in clang. Wir gehen davon aus, dies zuzulassen, sobald dieser Fehler behoben ist. Discussion thread |
Verbotene C++11-Bibliotheksfeatures
| Feature | Snippet | Description | Documentation Link | Notes and Discussion Thread |
|---|---|---|---|---|
| Aligned storage | std::aligned_storage<10, 128> |
Uninitialized storage for objects requiring specific alignment. | std::aligned_storage | MSVC 2017's implementation does not align on boundaries greater than sizeof(double) = 8 bytes. Use alignas(128) char foo[10]; instead. Patch where this was discovered. |
| Bind Operations | std::bind(function, args, ...) |
Declares a function object bound to certain arguments | std::bind | Use base::Bind instead. Compared to std::bind, base::Bind hilft, Lebensdauerprobleme zu vermeiden, indem das Binden von Capturing-Lambdas verhindert wird und Aufrufer gezwungen werden, Raw Pointer als Unretained. Discussion thread |
| C Floating-Point Environment | <cfenv>, <fenv.h> |
Provides floating point status flags and control modes for C-compatible code | Standard library header <cfenv> | Banned by the Google Style Guide due to concerns about compiler support. |
| Date and time utilities | <chrono> |
A standard date and time library | Date and time utilities | Overlaps with Time APIs in base/. Keep using the base/ classes. |
| Exceptions | <exception> |
Enhancements to exception throwing and handling | Standard library header <exception> | Exceptions are banned by the Google Style Guide and disabled in Chromium compiles. Note that the noexcept specifier is explicitly allowed above. Discussion thread |
| Function Objects | std::function |
Wraps a standard polymorphic function | std::function | Use base::Callback instead. Compared to std::function, base::Callback directly supports Chromium's refcounting classes and weak pointers and deals with additional thread safety concerns. Discussion thread |
| Ratio Template Class | std::ratio<numerator, denominator> |
Provides compile-time rational numbers | std::ratio | Banned by the Google Style Guide aufgrund der Sorge, dass dies mit einem stärker Template-orientierten Schnittstellenstil verbunden ist. |
| Regular Expressions | <regex> |
A standard regular expressions library | Regular expressions library | Overlaps with many regular expression libraries in Chromium. When in doubt, use re2. |
| Shared Pointers | std::shared_ptr |
Allows shared ownership of a pointer through reference counts | std::shared_ptr | Für Chromium ist noch deutlich mehr Evaluierung erforderlich, und derzeit gibt es nicht genügend Nachfrage nach dieser Funktion. Google Style Guide. Discussion Thread |
| Thread Library | <thread> and related headers, including
<future>, <mutex>, <condition_variable> |
Provides a standard multithreading library using std::thread and associates |
Thread support library | Overlaps with many classes in base/. Keep using the base/ classes for now. base::Thread is tightly coupled to MessageLoop was einen späteren Austausch erschweren würde. Wir sollten prüfen, ob sich unsere Locking-/Synchronisationsklassen durch Standard-Mutexe, unique_lock usw. ersetzen lassen. |
Verbotene C++14-Bibliotheksfeatures
Dieser Abschnitt listet C++14-Bibliotheksfeatures auf, die in der Chromium-Codebasis nicht zulässig sind.
| Feature | Snippet | Description | Documentation Link | Notes and Discussion Thread |
|---|---|---|---|---|
std::chrono literals |
using namespace std::chrono_literals;
auto timeout = 30s; |
Allows std::chrono types to be more easily constructed. |
std::literals::chrono_literals::operator""s | Banned because <chrono> is banned. |
Fazit
Den Quellcode bekannter Open-Source-Projekte zu untersuchen und ihre Design- und Implementierungsentscheidungen nachzuvollziehen, ist eine der besten Möglichkeiten, effizienten Code schreiben zu lernen. Bekannte C++-Projekte werden in der Regel von erfahrenen C++-Entwicklern gepflegt, die sich um die Anwendung bewährter Praktiken bemühen.
Kurz gesagt: Werfen Sie einen Blick auf den Chromium-Quellcode – die investierte Zeit lohnt sich.
