Information hiding

From Team 449 Wiki

Information hiding (also called encapsulation) is the practice of limiting which parts of the code can interact with each other in order to make a complex system of code easier to understand, use, and modify. For more information, see Wikipedia's article on it. This page details how we use information hiding in our code.

A simple diagram of which parts of the code interact with each other

General

All fields in all classes (except possibly Robot.java) should be private or protected and, if possible, final. This prevents them from being modified if they shouldn't be modified, and allows you to regulate any changes that happen via limitations on the setter. Because we often reconfigure the file system and plan to move things into 449-central and use them from there, making methods and classes package-private is discouraged as it most likely will break things later on. Just stick to public, private, or protected.

Commands

Except for commands for single-implementation subsystems, commands should always take either an interface or a generic of multiple interfaces, not a subsystem/implementation. This allows a command to work with any implementation of a subsystem, no modifications necessary.

Subsystems

Subsystems should implement interfaces relevant to what they do. While commands shouldn't reference subsystems, subsystems sometimes must reference commands to set their default command, which is fine.

Writing code with information hiding in mind

In order to actually benefit from information hiding, you need to write your code with it in mind. Don't just write code as if everything were public, with all private fields exposed through getters and setters - this is often worse than making no attempt at encapsulation, as it does not effectively hide information and simply adds overhead. Instead, first think about what your other code needs the object to do, and give it no more public-facing methods than are needed to accomplish this. A good way to do this is to design your objects "top-down," i.e. writing the higher-level code before the lower-level in order to more easily see what will be required of the lower-level objects. In more concrete terms, this would mean: design the command, then the interface used by the command, then the subsystem implementing the interface. In some cases (such as when writing first-draft "proof-of-concept" code for new hardware or functionality), this may not be feasible and code will have to be built "bottom-up;" however, in such cases, the code should later be given a top-down revision/rewrite once the new functionality is thoroughly understood and working. For more information, see Interfaces.