The document discusses strategies for working with legacy C++ code, including gaining control over legacy code through iterative refactoring while ensuring existing functionality is maintained. It emphasizes learning what the code does, making sure it continues functioning properly, and making gradual improvements. Specific techniques mentioned include writing tests, creating fake objects to inject into code under test instead of real dependencies, and using templates or friendship to fake classes that are otherwise difficult to mock.
8. The good news and bad news
There’s a lot of legacy C++ Code
There’s a good chance you’re doing it
C++ makes it easy to make critical mistakes
C++ is a powerful language
9. Gaining control over legacy code
To stop fearing legacy code:
1. Learn what the code does
2. Make sure it keeps doing it!
3. Iterative improvement via Refactoring
10. This is a unit test (GTest)
TEST(HolyGrailTests, WhoWeAreTest)
{
Knight knight;
ASSERT_EQ(“Ni!”, knight.Say());
}
11. A quick reality check
• Code have dependencies
• Refactoring == code change
• Code change == breaking functionality (78.3%)
• Breaking functionality go home == false
12. Sensing and Separation
public void SendEmailTest()
{
auto sut = new ...
User user;
sut->SendEmailToUser(user);
// Sensing problem
ASSERT???
}
void SendEmailToUser(User user)
{
EmailClient client;
// Separation problem
client.Send(user.Email, ...);
// Important business logic
...
}
13. “My focus is to forget the pain of life.
Forget the pain, mock the pain,
reduce it. And laugh.”
Jim Carrey
14. The problem - dependencies
My Code
DB
Files
Files
Files
Files
Services
18. Not all dependency
are created equal
Some are harder/impossible to fake
Non virtual
methods
Hard to
inherit
classes
Static
method
calls
Singletons
Internally
instantiated
Heavy
classes
20. Friend is your friend
class MySingletons;
class Rectangle
{
int width, height;
public:
friend FakeRectangle;
};
21. Problem: un-fakeable methods
• Static methods
• Hard/impossible to instantiate class
• Non-virtual methods
Cannot be inherited == cannot be injected!
22. Using templates for injection
Compile time duck typing a.k.a hi-perf dependency injection
• Can fake unfakeables
• Can fake internally instantiated classes
A method (code)
that tests specific functionality,
Has clear pass/fail criteria
and runs in isolation
Dependencies == other classes
External libraries
Other resources
Outside of our control
Dependencies related Issues
Hard to instantiate class in test
Difficult to run methods in test
Impossible to assert results
Dependencies == other classes
External libraries
Other resources
Outside of our control
Dependencies related Issues
Hard to instantiate class in test
Difficult to run methods in test
Impossible to assert results
Modernize old C code
Move to C++/11/14/17 …
Extract functionality from existing codebase
New platform support
New tool support
Optimization
Build time
Run time
Developer isolation