Public, protected, private or even final?

Svaťa Šimara
Carvago Devs
Published in
3 min readFeb 3, 2021


We use access modifiers to hide certain properties or methods — public, protected, private. Final is used to disallow children. But why would we hide something or disallow anything? Why to do such things?

We have to often implement new features or modify existing ones. This results in extending current code, extending parameters of methods and ultimately to the code refactoring.

Discount Functionality

Let’s assume following code — it deals with Orders and we allow applying percentage discount to the whole order. This percentage discount is applied to all order items.

The getDiscount() method is public because it seems nice to provide this functionality to programmers, so they don’t have to repeat it.

As we can see, the price is represented as an integer.

We don’t care about the Item in this article, but if You cannot think about the code without the class and return types, here is the Item

New Feature

We have to support multiple currencies in our system.

After a short research, we realize there is a good library brick/money that deals with currencies and even with decimal numbers correctly. So we are going to use it instead of integers.

Obviously, the Item have to work with the Money class

The Order class now looks like

So far good. We implemented the new feature.

Changes in the System

We changed the class Order, specifically the class interface
from getDiscount(int $price, int $percent): int
to getDiscount(Money $price, int $percent): Money

But this isn’t the end of changes. We have to adjust also

  • All internal usages of this method (done, by the change in the Item)
  • All outside usages of this method — because it is public
  • Interface of all descendants — because the might be descendants
  • All usages in descendants— because descendant might use it

Quite a lot of work. And why? Because we wanted to allow our colleagues to use the getDiscount(), as we assumed it might be practical. Really a lots of work just because of an assumption, not because of a real need.

Doing Less Work

Requirements changes, therefore the code changes as well, we refactor the code by new needs, and that’s our job.

Let’s protect our code, so we have to do less changes.

We protect the code by private and final modifiers

Let’s repeat how much work do we have to do when we change the interface of the method getDiscount()

  • All internal usages of this method (yes, there is no way around)
  • A̶l̶l̶ ̶o̶u̶t̶s̶i̶d̶e̶ ̶u̶s̶a̶g̶e̶s̶ ̶o̶f̶ ̶t̶h̶i̶s̶ ̶m̶e̶t̶h̶o̶d̶ — no, it’s private
  • I̶n̶t̶e̶r̶f̶a̶c̶e̶ ̶o̶f̶ ̶a̶l̶l̶ ̶d̶e̶s̶c̶e̶n̶d̶a̶n̶t̶s̶ — no, it’s final
  • A̶l̶l̶ ̶u̶s̶a̶g̶e̶s̶ ̶i̶n̶ ̶d̶e̶s̶c̶e̶n̶d̶a̶n̶t̶s̶ — no, it’s private and final

If we protect internals of classes, we will become free to change internals, even implement new features, without doing a lots of effort.

Private and Final

If we accept final and private as a default state, we unlock the ability of refactoring and introducing new features without too much pain. Especially when working in a team where everyone uses everything.

Use public, protected when have a Reason

When a teammate need to create descendant, use private method in descendant, use private method from outside, no problem. The teammate changes the default state. Removes the final, softens the visibility from private to protected or to public.

But we do it only when we have a reason for doing so. And such reason have to be mentioned in the version control system (eg. GIT), so every teammate is aware why did someone changed the default state.


Mark everything private and final, and You’ll do less work.



Svaťa Šimara
Carvago Devs

Developer interested in Domain-Driven Design & Modeling