Refactor a smart home controller toward the Dependency Inversion Principle without changing its behavior. Setup is complete when all four starter tests pass.
This kata complements Clean Code: SOLID, Ep. 13 - Dependency Inversion Principle.
In this exercise, you'll practice refactoring code to adhere to the Dependency Inversion Principle (DIP). You'll be working with a smart home system that controls different types of lights and air conditioner.
The initial code consists of several device classes and the
SmartHomeController class, which is responsible for controlling all the
devices (lights and air conditioner).
However, the initial code violates the Dependency Inversion Principle, as the
SmartHomeController class directly depends on concrete classes. In the tests,
we also directly manipulate the dimmable_light and networkable_light
instances to check their unique behaviors.
Your goal is to refactor the code to adhere to the Dependency Inversion Principle and make it easier to implement new devices.
Here are some guidelines to follow:
-
Introduce an interface or several interfaces (or abstract base classes) for the devices that the
SmartHomeControllerinteracts with. -
Update the
SmartHomeControllerclass to depend on this interface, instead of the concrete device classes. -
Update the devices to implement these interfaces.
-
Modify any constructors or method calls as necessary to accommodate the refactoring.
Note
Remember that in this exercise, we assume all devices are in an ideal state and don't account for error cases such as a network connection failure or an attempt to dim a light below 0% or above 100% brightness.
Make sure the program still behaves the same way after your refactoring. There's a unit test in place that checks that on a very rudimentary level by just looking at the output of the program.
When you're done with refactoring, test the quality of your refactoring by
implementing two additional scenarios (methods) in SmartHomeController:
-
Add the
make_quick_breakfastscenario to open the blinds and make a predefined coffee type.- Add
Blindsdevice class withopenandclosemethods (blinds are always powered and does not have an on/off function). - Add
make_quick_breakfastmethod toSmartHomeController.
- Add
-
Add automatic vacuum cleaner and the
schedule_night_cleaningscenario, which should start the cleaning once everything else is turned off.- Add
VacuumCleanerdevice class withstart_cleaningandstop_cleaningmethods. - Add
schedule_night_cleaningmethod toSmartHomeController. After calling this method, the vacuum cleaner should start cleaning once all other devices are turned off.
- Add
Evaluate whether your refactoring made life easier for you or not.
Required:
- Git
- A compiler with C++17 support. Choose one:
- GCC 10+ on Linux
- LLVM Clang 14+ on Linux
- Apple Clang 17+ on macOS
- MSVC 2022 on Windows
- CMake 3.24 or later
Optional:
- GNU Make, for shorter commands. Every required task also has direct CMake and CTest commands. Make may be unavailable on Windows.
You do not need to install GoogleTest separately. CMake finds an installed copy or downloads the pinned release when needed.
-
Clone the repository:
git clone https://github.com/Coding-Cuddles/smart-home-refactoring-cpp-kata.git -
Enter the repository directory:
cd smart-home-refactoring-cpp-kata -
Run the starter tests. Use Make when it is installed:
make testOtherwise, use CMake and CTest directly:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug cmake --build build --config Debug ctest --test-dir build --build-config Debug --output-on-failure
The first run may download and build GoogleTest. CTest should report
100% tests passed.
If a command reports a missing compiler or CMake, install that prerequisite and run the setup commands again.
Setup is complete when CTest reports 100% tests passed.
-
Refactor
smart_home.hwhile preserving the behavior covered bytest_smart_home.cpp. -
Run the tests after each change. Use Make when it is installed:
make testOtherwise, use CMake and CTest directly:
cmake --build build --config Debug ctest --test-dir build --build-config Debug --output-on-failure
Continue when CTest reports
100% tests passed.
Make is optional. Run make or make help to list these commands in the
terminal.
| Command | Result |
|---|---|
make all |
Build and run the test suite |
make help |
Show the Make command reference |
make build |
Configure and build without running tests |
make test |
Build and run the test suite |
make format |
Format tracked C++ and header files |
make format-check |
Check formatting without changing files |
make clean |
Remove generated build artifacts |