Iceberg Classes

An “Iceberg Class” is loosely defined as a class with more private than public methods, but we will be specifically talking about those classes with only one or two public methods (other than an initializer).

Besides letting you get away with not testing most of the methods, Iceberg Classes also benefit from being much more likely to have only a single responsibility, tend to be extremely easy to read, and are easy to refactor.

When a class only has a single method as its interface, it becomes more difficult—though not impossible—for it to be in violation of the Single Responsibility Principle. Hints that you may be violating SRP in an Iceberg Class include use of conditionals, different types of return values, too many public methods, and long methods.

Speaking of long methods, I find that one of the big reasons to write an Iceberg Class is to extract methods that are short with names that are so descriptive that you don’t even need to read their bodies to know what is happening:

class Registration
  def initialize(attributes = {})
    @user =

  def save
    user.valid? && create_user


  attr_reader :user

  def create_user

  # ...

The details you cannot see, cannot be used directly in other classes. Therefore it is much easier to change the private part of the class than the interface part of the class. This is important because many classes are likely to change a lot during their lifetimes.

Refactoring Iceberg classes is quite easy, since most of the content of the class is ‘below the fold’ of the private keyword, which means that most of the time you won’t need to make changes outside of the class as a part of the refactor.

This is because the private methods should never be accessed from outside the class, making it is safe to refactor within that class without worrying about breaking other classes (which only use the public interface) or tests (which should not be covering private portions of the class directly).

The Iceberg Class pattern works best in classes which are Service Objects or which model business practices, such as FriendshipCreator, ArticleImporter, or Search. It is not suited to value objects, database models, etc.

It is important when building classes to avoid replicating logic or leaving behavior that belongs in a value object. Duplicated logic should be extracted into service objects, such as the logic to find the dom_id of an object (user_23 or post_12). Also consider creating value objects so that logic such as GeocodingClass#calculate_distance_between(x, y) can be organized with the data it operates on: Point#distance_to(point).

Iceberg Classes provide a great way to write code that requires a minimum of tests, is self-documented, and is simple to refactor. There are a few things to be wary of, such as that you are hiding behavior which belongs elsewhere and that you are not using the pattern where it doesn’t make sense. I encourage you to give Iceberg Classes a try, and let me know how it works for you.