Hacker News new | past | comments | ask | show | jobs | submit login

Change your API then.

In this case you usually have 2 classes : a low-level algorithm-specific one, used by a higher-level consumer-centric one.

Most of the time, testing private methods is a poor solution to a larger design problem.




Why expose the low-level algorithm-specific stuff in your public API at all, though?

I don't think "just for testing purposes" is a good answer. Unit testing hooks shouldn't be in the public API of a library.


This is also good for maintainability. Say you need to upgrade the algorithm but keep the old version around. You can create a new version of the algorithm specific parts without changing the public implementation and allow users to select which version to use; eventually changing the default. In a single class, this would be a nightmare.


"Nightmare" is a bit strong; that seems like a very normal and straightforward refactoring step... iff you avoided putting the low-level stuff into your public API.


I’ve mostly see people do public_namespace.private_internal.MyClass so you can use it if you really want to… but you probably shouldn’t.


Well, don't expose them then?


I see this as the main tension in the extracting-class viewpoint. Assuming your language allows it, you can extract out a class that's still private to the current package, meaning that the public API is unchanged. But there are still costs to extracting out that class.

If the one public method just calls private method A, B, and C in order, passing the result of one step to the next, and if we don't need to handle different variants of A, B, and C (meaning dependency injection is not necessary), we arguably don't gain much from splitting the original class in two. We're left with a very small class of a single method that's tightly coupled to the extracted class. We can remove the coupling with dependency injection, but now we need to add some code that actually injects that dependency at runtime. So understanding how the pieces fit together is harder. The only benefit to splitting the class that I can think of is in preparing for a future situation where orchestrating the three helper methods becomes more complex, or where you actually do need to handle different variants of A, B, and C via dependency injection. But it feels like premature abstraction to me, single responsibility principle notwithstanding.


I see this as the main tension in the extracting-class viewpoint. Assuming your language allows it, you can extract out a class that's still private to the current package, meaning that the public API is unchanged. But there are costs to extracting out that class.

I don't see why the class needs to be extracted in that case. If it makes the code easier to follow, do it; if it adds bloat and boilerplate, don't do it.

The key thing is the ability to expose stuff for testing only, not in the public API. Depending on the language, you might not need to extract a class at all -- just make some fields or methods package-private.

I guess if your language doesn't provide a way of doing that, extracting a class is a reasonable workaround because you can segregate your public API into high-level and low-level parts, and recommend that end users avoid the low-level parts. But that's not ideal; better to hide the low-level stuff if you can.


To be clear, I was responding to the combined argument of the above comments: that you should split the class but not expose the extracted class in the public API. I agree that there are cases where we don't need to extract the class, but am willing to be convinced otherwise.


Any API changes to this would have bigger drawbacks than just making the tests friends of this class.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: