- Understanding Interfaces
- Defining Interfaces
- Finding the Public Interface
- Writing Code that Puts its Best (Inter)Face Forward
- Public, Protected and Private Keywords
- The Law of Demeter
- Summary
Writing Code that Puts its Best (Inter)Face Forward
The clarity of your interfaces reveals your design skills and reflects your self-discipline. Since design skills are always improving but never perfected, and since even today's beautiful design may look ugly in light of tomorrow's requirement, it is difficult to create perfect interfaces.
This, however, should not deter you from trying. Interfaces evolve and to do so they must first be born. It is more important that a well-defined interface exist than that it be perfect.
Think about interfaces. Create them intentionally. It is your interfaces, more than all of your tests and any of your code, that define your application and determine it's future.
The following section contains rules-of-thumb for creating interfaces.
Create Explicit Interfaces
Your goal is to write code that works today, that can easily be reused and that can be adapted for unexpected use in the future. Other people will invoke your methods; it is your obligation to communicate which ones are dependable.
Every time you create a class, declare its interfaces. Methods in the public interface should:
- Be explicitly identified as such
- Be more about what than how
- Have names that, insofar as you can anticipate, will not change
- Take a hash as an options parameter.
Be just as intentional about the private interface; make it inescapably obvious. Tests, since they serve as documentation, can support this endeavor. Either do not test private methods or, if you must, segregate those tests from the tests of public methods. Do not allow your tests to fool others into unintentionally depending upon the changeable, private interface.
Ruby provides three relevant keywords: public, protected, and private. Use of these keywords serves two distinct purposes. First, they indicate which methods are stable and which are unstable. Second, they control how visible a method is to other parts of your application. These two purposes are very different. Conveying information that a method is stable or unstable is one thing; attempting to control how others use it is quite another.