After my realization that Groovy doesn’t actually allow private methods or fields, I returned to doing some work with Python. I like Python for the data science libraries behind it. But now, after doing work in Kotlin, Java and Qt’s C++… returning to Python was like walking home only to realize home wasn’t the grand place you remember…
Revisiting Python, the issue of Encapsulation came up. To my surprise, Python (like Groovy) also doesn’t have any real “Private” method.
The defenders for this have their claims… mostly it can be surmised as the following Stack Overflow comment:
Python is big in security circles for its Penetration Testing suites and libraries. But now we’re looking at Python from the opposite angle… a language for building applications.
The above comment from Peter says that “Remember, encapsulation is not even weakly related to ‘security’, or keeping the kids off the lawn…”
Let’s play that out… If you’ve been involved with development teams, you’ll know that teams have hard deadlines, pressure, and turn over. Some teams get dozens of devs turned over in a single year.
Considering that pace, imagine a situation where we have a web application. It has a user creation Class and this class makes use of several methods. Let’s assume that two of the methods called to perform fraud checks. One might call a 3rd party to get a domain score for a user’s email submitted through registration. Another might verify the user’s geoip, which may violate terms and conditions.
A final method (that should be private) is called when the fraud checks are complete. It performs the actual registration of the new account.
Some new dev’s are hired and tasked with creating an API for 3rd party affiliate sites to call to register new users. They don’t want to recreate the whole user creation process, so they decide to repurpose the original code for user creation…
The dev’s who wrote that original user creation methodology may not even exist at the company anymore. So they go in thinking they will reference that code.
These new dev’s inherit from the User registration class… and they see there’s a method available called, “user_registration(….)” They make use of it allowing it to be part of this public API endpoint.
What they may fail to notice in their haste, is that this method should only be called after all the fraud checks are validated. They have simply bypassed fraud.
They might notice that the method they are calling has params like:
If clear enough, they should know to invoke the fraud methods before attempting this. Maybe they do… or maybe they are lazy devs and they simply pass in a value… maybe they don’t understand domainScore being the score of the domain of the user registering, and instead pass in the domainScore of the affiliate website. The same ambiguity might exist for the geoIp param as well.
Now we have a public endpoint where people are signing up from geoip’s that are forbidden, as well as domains with domain scores that are far too low.
Alternative (Using Private)
In the same scenario above, imagine they are using a language with proper private method enforcement. The new dev’s inherit from this User registration class.
This time however, they do not get access to the user_registration method. Instead they are only allowed access to a setter for a specific method that starts the registration process, calls the fraud methods and finalizes this into a database save method (which is private.)
Without enforcement of private methods and fields, you are left with humans being perfect. They must maintain and validate that their actions won’t bypass security, business logic and the like.
This kills Python for me, and I find that sad. I love Python as a data science tool… and yes it’s still quite good for that… but it’s failing on the one thing it’s been hailed for – Security. So while Python is fine in Jupyter notebooks, or data science… making a public facing application with it, opens a slew of problems.
If you can’t properly encapsulate and make things private, you end up with team members who make mistakes that are catastrophic.