Kinda private methods using classes

Kinda private methods using classes
0.0 0

#1

I’m developing a library for common use. One of the classes will have a lot o of methods, some of them should not be visible for people using them. Not for security reason, just to make a concise and simple API.

I decided to approach this, in a way similar to what revealing module pattern do. One thing that bothered me from this patter is the impossibility to unit test “private” methods. To handle that, I took inspiration from java’s decorator pattern, in the sense that the exposed class has a HAS-A relationship with the base class, exposing only the “public” methods.

I think it’s best to explain by example


//--- Base.js --- 
//This class methods are not really private  
class Base {
  privateMethod1() {
    console.log('foo');
  }

  // this method is the "private"/hidden one. Not accessible from Exposer instances
  privateMethod2(){
  	console.log('foo2')
  }

}
export default Base;

//--- Exposer.js ---
import Base from './Base.js'
const BASE = Symbol('base');
class Exposer{
  constructor(initArgs) {
    this[BASE] = new Base(initArgs);
  }

  public1() {
    this[BASE].privateMethod1();
  }
}

export default Exposer

A couple of things should be observed:
1 - Base class could/should be used for unit testing;
2 - Exposer class should not really implement any logic;
3 - Library will only expose Exposer class;

I have a couple of questions regarding this:

1 - Is there anything to be considered a bad practice ?
2 - Appart from extra boilerplate, what other cons are there ?


#2

Have you decided which way to go? I struggled with this too when creating my library.

I would get a small version working first, then check the performance of your app because when I tried using symbols, my library was pretty slow so I ditched that pattern as privacy < performance because it is not a crypto library or anything like it.

I would like to hear more about your library :slight_smile:

Maybe there is a well-suited pattern for it


#3

Straightaway, without looking at the code, the requirement that you want to test private methods (I’ll have a look at the code when I don’t have a baby sleeping on me though).

Also, why write a class for those private methods? Why not just write functions? I think they’re all accessible via reflection as well, but would need to check. At the minute generally WeakMaps are the solution for private properties, I think that’s the only way currently you can get what you’re trying to do here. (Also there should be a polyfill for the private fields proposal floating around, but it’s a syntax change so would need to transpile with Babel)


#4

Hum… I did not know about the performance bottleneck. I’ll check it and let You know.


#5

Well… The module must have instances. It’s not something like lodash. Think of it more like a Express server. I think classes keeps the code well organized and fell like “the way it’s done now”. I know I could get the same results using a function (as the revealing pattern mentioned). But again, It makes the private scoped functions hard to unit test. I would have to export them on the module somehow. Or maybe I’m missing something here.

Yeah… That’s not a problem. It’s not like I want to completely prevent the lib user to access those method. It’s just more of a suggestion to what methods the user could/should be using (in chrome debug or IDE intelisense). If someone tries really hard to get those methods, it could be possible, but should fell hacky to do so. I’ll try the WeakMap suggestion.

I’ve seen the pattern. It’s still on stage-3 and a lot of discussion going on about the basic syntax of it. I’m not comfortable to rely on that. Beside, I not sure You could access those properties somehow to unit test them.


#6

So to make a simple API you want to make functions “not visible” but still available to test, and you want to use classes not functions, and leave it still possible for the user to access those “private methods”. So at the end of the day you would want to discourage the use of these methods, still be able to test them and “not be visible”

The only thing I know that could help in this conversation besides what @DanCouper said is just using the underscore prefix convention. Taking a “pythonic” approach seems like the simplest, overhead-less, most direct method. Yes the methods are still “visible”, but its up to the programmer using your lib right? Otherwise if they DO need to use you (for whatever hotfix they just must do), they have easy access to it.

I can understand making the lib cleaner, but this is a library right? I’m not sure if designing the entire lib around the idea of making the library interface cleaner is worth any overhead of making things more complicated. I’m not sure what the library will be used for, but whatever it does it should do well and that’s all. No need for extra complexity. Its one of the reasons why Lodash is so popular.


#7

Ah that’s not quite what I meant re. unit testing. Why do you want private methods to be unit testable? There’s no reason for them to be. A class instance is a black box, you interact with it via public methods, and test those methods, the private stuff should just be internal machinery that just facilitates the public stuff.

This is the reason I said why not use functions. If they’re in a different module and are stateless, then they’re easy to test. If you’re importing a class you inherit from, you now have state for one thing in two places, and w/r/t to testing and debugging, state in one place is hard enough to deal with.

If you’re not that interested in actual private methods, then just make them all public and put an underscore in front of the ones that are private, as @bradtaniguchi says