Making a method public is quite simple.
It only requires you to add a simple keyword to the method definition. It also lets you enjoy an easier development process. You don’t have to mull over which access modifier to put on a method if the default is public. It also guarantees that you can access the method from another class or package under any circumstance.
But does that mean making all your methods public is a good practice for a programmer?
As a general rule, don’t make all methods in a class public by default. That goes against the principle of encapsulation, makes your code less maintainable, and can lead to big interfaces.
Let’s see in more detail what could be some complications with public methods.
Why you shouldn’t make all methods public by default
As stated above, there are three main reasons why you should not make all methods public by default. Let’s address them one by one.
1. It goes against the principle of encapsulation
In object-oriented programming, encapsulation gives a blueprint for achieving loose coupling between components. It encourages you to hide certain information on the component’s inner workings so that outsiders only see the things that concern them, nothing more.
If you make all methods in your classes public, you’re taking a road opposite to what encapsulation recommends. Instead, it opens all the doors and windows for outsiders to peek into the logic that handles the data.
This creates a situation unfavorable to the developer and the users relying on your implementations.
One purpose of information hiding in encapsulation is to make your code simpler to understand and use. Exposing only a class’s key properties and behavior allows users to quickly understand its abilities without going into exacts. When mixed with abstraction, this power helps you to tie your code to object behavior instead of their implementations.
If you grant access to all methods of a class, it induces an information overload that compels users to form unnecessary couplings between objects. In addition, this lack of emphasis on the class’s main responsibilities makes your code difficult to understand without significant effort.
From a pure developer perspective, this practice produces less secure code that allows users to understand how you internally handle data. Public access it grants to all getters and setters also beats the purpose of giving private attributes to a class.
Another major downside to this loss of encapsulation in the code is how it complicates your future maintenance and modification efforts. The following section goes into more detail on this issue.
2. It makes your code less maintainable
As you saw in the previous section, making all methods in a class public can result in tight coupling between objects. This bad design comes back to bite you whenever you try to change something in the code during maintenance.
These public methods provide users a free pass to directly rely on any or all logic in your classes. Some of them may be internal logic that doesn’t serve much purpose to the users. Some may contain code that goes through significant changes over time. You may even want to remove or rewrite certain methods to resolve bugs and improve performance.
This freedom creates a situation where users heavily employ your methods that handle internal logic. It limits your ability to introduce changes to your code without breaking the system and forcing others to modify their code.
That’s how too many public methods create a domino effect that leads from one bad design decision to another. The fall starts with a lack of encapsulation. Eventually, it bleeds into a lack of abstraction, considering how interrelated one is to another in OOP. The two combines to produce tight coupling between components in your system. It leaves you with a codebase that requires time and effort to maintain or modify in the long term.
3. Too many public methods can propagate to the interface
A class with many public methods can compel programmers to include all its methods in its interface. This is particularly true in cases where the interface has only one concrete implementation.
Why is it concerning? It puts you at the risk of creating fat interfaces, each with too many methods.
While an interface with many methods isn’t always a result of bad design, it binds you to an inconvenient contract in this scenario. When you include an object’s internal behavior in an interface, you agree with the users to support them through your code.
So, what happens if you want to change this internal behavior to provide better support for the class’s main functions? First, you have to break your agreement with the users. It comes at the cost of inconveniencing the users who rely on your code. It also stains the trust they have put in you because you stopped delivering what was promised.
Keep methods private by default
If making methods public by default is not a good practice, what should you do instead? You should keep the methods, and variables, private by default.
Making a method private prevents anyone outside its class from accessing it. This eliminates the chance of any other class creating a coupling with the object through the method. It lets you have a smoother maintenance experience without worrying about internal modifications affecting other users or classes.
Setting methods private by default also allows you to hide complexities in your code through encapsulation. Users get to simplify their interactions with objects since you’re only exposing their core functionality to the public.
So, whenever you write a class, you should make it private if you are not 100% sure which access modifier to give to a method. If you later come across a reason to use the method outside the class, updating it with a new modifier won’t cost you more than a few seconds.
The same goes for other users relying on your implementations. They can request access to a method currently set to private if needed. You can weigh the pros and cons of the decision and give the minimum access level required for the task if it’s justified.
What about unit testing private methods?
One last question you might have is: Is it bad practice to make methods public solely for the sake of unit testing?
Since you can’t directly write unit tests for private methods, how can you ensure they function as expected? Well, you have to test them through the public methods in your class or modules.
Then, the failure in a public method’s test case can indicate a bug in the private method.
If your private method contains a logic too complex to test via public ones, it can be a sign that you should change the code:
- One solution to this is refactoring your code to simplify the method.
- If that isn’t possible, maybe you should move the method to another class and change the modifier to internal access. A different class may provide a better home for the private method.
- If this isn’t possible, it could be a sign that you contain the responsibility of a separate class inside a method. In this case, you should create a new class to include its logic and give it suitable access modifiers.
Sometimes, developers make any method that doesn’t demand a specific access modifier public by default. But that’s not the best practice. It can increase code complexity and causes tight coupling. It also reduces the system’s maintainability and inconveniences outside users with constantly changing implementations.
But if you resort to using private methods by default, you can avoid many of these problems. In addition, it allows you to re-establish the encapsulations in your code to give it a better design that makes your life easier in the long term.