The moose likes Developer Certification (SCJD/OCMJD) and the fly likes Properties/Settings - a design question Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Certification » Developer Certification (SCJD/OCMJD)
Bookmark "Properties/Settings - a design question" Watch "Properties/Settings - a design question" New topic
Author

Properties/Settings - a design question

Philippe Maquet
Bartender

Joined: Jun 02, 2003
Posts: 1872
Hi everybody,
I feel a bit uncomfortable with one of my designs, not because I cannot justify it, but because it transgresses the
Avoid Public Access to Instance Variables taboo, and because I make a broad use of it in my application.
(Excerpt of Sun's Recommended Programming Practices)
Don't make any instance or class variable public without good reason. Often, instance variables don't need to be explicitly set or gotten-often that happens as a side effect of method calls.
One example of appropriate public instance variables is the case where the class is essentially a data structure, with no behavior. In other words, if you would have used a struct instead of a class (if Java supported struct), then it's appropriate to make the class's instance variables public.

I love to transgress taboos when I find good arguments to do so. And I do think I have them here. But I know by experience that many people hate it, being reluctant before any argument can take place. And as I don't know my examiner yet, it would be nice to have your opinion in the meantime.
The context
We must store in suncertify.properties all properties which influence the behavior of our main classes in - at least - the db and network areas. In fact, it's the case of all properties we'd like to be modifiable at run time :
(instructions)
Your programs must not require use of command line arguments other than the single mode flag, which must be supported.
Your programs must not require use of command line property specifications. All configuration must be done via a GUI, and must be persistent between runs of the program. Such configuration information must be stored in a file called suncertify.properties which must be located in the current working directory.

Depending on your design, you may have a lot of such properties, even in additional areas : I personally need properties for logging and for the application as a whole.
We must use the Properties class to store/retrieve them. Properties is a HashTable mapping property names (String keys) to their String value.
As our suncertify.properties may be shared by our three applications (server/client/alone), it may be useful to prefix the property names to ensure their unicity.
The problems
At the datastore level (class Properties), you face all the values conversion issues (from String to native types and inversely). If you have array properties (I have such ones for logging), the job is even a bit more complex.
At the classes level (the ones which uses properties), it's hard to deal with them too :
  • You ideally need one setter/getter pair per property
  • It may be difficult to validate an individual property in its setter, if its correctness depends on another property (ex. : int minX and int maxX, where minX must be lower or equal than maxX : to set them both from 20,30 to 40,60 setMaxX() must be called before setMinX() or the call will fail. And inversely to reset them to their previous value...
  • Some properties are related to each other not for validation only, but because changing any of them may fire some action while all of them are used by the given action. Ex.: changing the IP Address or the listen port of your server could make it reset its listening process. But as both of those properties are used in the reset process, you probably won't initiate it automatically from any of the corresponding setters.
  • As there is no central place where to group your properties, you need at least to document your class to make clear, among your numerous instance variables, which are properties and which are not.
  • As properties are not seen as a whole, classes which use many of them may become hard to maintain.


  • At the GUI level
  • Typically, such a GUI will need some in-memory container to store/retrieve properties. And sometimes, an instance of the class the properties belong to cannot play that container role : it's impossible when some of the properties are needed at construction time, and it's not desirable anyway because changing an individual property may influence - by definition - that instance's behaviour. So you'll need a specific class just to play the container role and it will make your code a little more cumbersome.
  • As the GUI writer, as you have no way to validate the properties as a whole, you'll need to write validation routines yourself, probably at the GUI level, which is bad practice, but also supposes that you get some deep understanding of the related class.


  • The Design Pattern
    I didn't find a name for what I did among the patterns I know by name, and I am afraid Andrew will call it the TransgressedPublicTaboo pattern ...
    I will post here the minimum of code I think that without it it would be difficult to discuss :
  • my Settings interface with a few comments which are the embryo of a future JavaDoc ;
  • my AbstractSettings class, with no code because it implements by itself 98% of the Settings interface ;
  • a short example of a use of Settings
  • how a Properties fa�ade may use the Settings interface.



  • Now what do you think guys ? Is it acceptable to use public access for instance variables the way I do ?
    If a Settings obj is quite far from a simple "C struct", I personally think that the "spirit" of access limitation is respected if not the letter :
  • Settings are just data containers
  • None of the Settings methods are real "behavior" methods, just access helper methods and validation helper methods.
  • Classes which use Settings have easy ways to protect themselves against any risk related to the public access.


  • Thank you in advance for your comments.
    Best,
    Phil.
    [ October 30, 2003: Message edited by: Philippe Maquet ]
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11503
        
      95

    Hi Phil,
    Glad to see you are following the "keep it simple" rule
    I don't like having the variables public like this, although I can see that global properties might be one place where you might do this.
    (Digressing from your main question for the moment, I think that a properties wrapper class would be a good candidate for a singleton, and/or having static variables and/or static getters and setters).
    Taking some of your issues:
    It may be difficult to validate an individual property in its setter, if its correctness depends on another property (ex. : int minX and int maxX, where minX must be lower or equal than maxX : to set them both from 20,30 to 40,60 setMaxX() must be called before setMinX() or the call will fail. And inversely to reset them to their previous value...

    True, but you can cater for this by either having a setter method that will allow you to set both values simultaneously, or having a setter method that has a parameter to indicate whether the value should be validated or not.
    Having the variables public means that you have no thread safety. In the case you mentioned, you could be changing both values, and until both have been set, you have invalid values. If another thread reads those values at that point, it will have invalid and unusable values.
    If you have a setter, you can ensure thread safety. If the one setter accepts both values, then you can ensure that no other thread can get the intermediate values. If you have a setter that has a parameter indicating that this is an intermediate value, you can set an internal boolean indicating that the values may not be read through the getter at present.
    Some properties are related to each other not for validation only, but because changing any of them may fire some action while all of them are used by the given action. Ex.: changing the IP Address or the listen port of your server could make it reset its listening process. But as both of those properties are used in the reset process, you probably won't initiate it automatically from any of the corresponding setters.

    True, but this could be handled by having a setter with a "dontUpdateObservers" parameter.
    As there is no central place where to group your properties, you need at least to document your class to make clear, among your numerous instance variables, which are properties and which are not.


    As properties are not seen as a whole, classes which use many of them may become hard to maintain.

    Why?
    As I mentioned, I would see the properties class being a singleton, possibly with static getters / setters. So any class that needs to know the IP address simply calls MyProperties.getIPAddress() - why is this hard to read or maintain?
    Typically, such a GUI will need some in-memory container to store/retrieve properties.

    Well, I think we can have a single class to handle properties, which means that the users of the properties do not need to have their own container for this - they either need to use the value, or they need to store it in their own local variable as part of some other process.
    As the GUI writer, as you have no way to validate the properties as a whole, you'll need to write validation routines yourself, probably at the GUI level, which is bad practice, but also supposes that you get some deep understanding of the related class.

    I think this is an argument for having getters and setters on some class that just handles properties
    Regards, Andrew


    The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
    Philippe Maquet
    Bartender

    Joined: Jun 02, 2003
    Posts: 1872
    Hi Andrew,
    Thanks a lot for your many comments.
    Andrew:
    Glad to see you are following the "keep it simple" rule

    I understand the irony you put in that sentence, but I believe that - for once - I followed that "keep it simple" rule :
    I just refactored my server code to make use of my suncertify.util.settings package, and it looks like everything is by far much simpler than before.
  • My socket ConnectionsManager class used 7 properties, meaning 7 instance variables + 7 getters and 7 setters. And validation of some of them was hard to do. ConnectionsManager has now one private NetSettings + 1 getter and 1 setter. Validation is centralized which is easier to achieve.
  • Likewise, at the Table level (the multiton Data uses), I had 6 properties (and the same number of getters/setters), all replaced by 1 DBSettings instance and 1 getter/setter pair. Here also, validation is easier.
  • Refactoring the corresponding GUI classes was even more rewarding : the Settings interface offer them a standard way to get in one line their own private copy of the settings their are responsible for, to validate them in one line, and to store / retrieve them to / from a PropertiesFile, still in one line. Just the fact that all conversions are dealt automatically by AbstractSettings through reflection saves a lot of cumbersome and unintesresting code.
  • As the same framework will be used for my ApplicationSettings and LoggingSettings, I'll save a lot of code in implementing them.


  • Actually, my new code base is now much easier than before to read and maintain.
    Andrew:
    I don't like having the variables public like this, although I can see that global properties might be one place where you might do this.

    Neither do I. But thank you for the second part of your sentence : it's reassuring.
    I use the public Field[] getFields() method of the Class class :
    Returns an array containing Field objects reflecting all the accessible public fields of the class or interface represented by this Class object. The elements in the array returned are not sorted and are not in any particular order.
    As the Class.getFields() method exists, I suppose that Sun had cases in mind where using public instance variables would make sense and I hope this is such a case.
    I hesitated before doing so, but after having compared both techniques (a simple container of public variables (1) vs a container of private variables along with getters/setters (2)), I concluded that solution (1) offered many advantages :
  • When I implement a new Settings class, I save the time of writing one getter/setter pair per property.
  • As validation is better handled for the Settings object as a whole, the getters/setters would do nothing else than provide a public access to their corresponding private variable.
  • Accessing properties through getters/setters would make the reflection part of the job harder. Just think of the fact that Settings supports array properties for all native types and String. For them, I would need special getters/setters ...
  • In a Settings object, the convention used to identify properties is simple : there are all public fields, period. For instance, AbstractSettings stores a private prefix used to name properties. As it's private, it's automatically ignored. "public" acts as a "property-marker" and it's handy. If properties could be mixed with other instance variables at the same access level, I would need some other convention (based on the variale name ?), probably more complex to describe, remember, and follow.
  • I found that using reflection on public fields to support automatic two-way conversion on all native types, Strings and arrays of them was ... complex enough ! Sure Mark would agree with it.


  • Andrew:
    (Digressing from your main question for the moment, I think that a properties wrapper class would be a good candidate for a singleton, and/or having static variables and/or static getters and setters).

    Do you really think that ? I am surprised because :
  • I know you don't like the singleton patterns so much (and I agree with you)
  • It would be quite restrictive because classes which must support multiple instances with different settings values could not use that singleton or static properties container. I have a multi-tables db design : it makes sense that each Table instance gets its own DBSettings instance (maybe different cache settings but ... for sure a different file name).


  • ---------------------------
    Phil:It may be difficult to validate an individual property in its setter, if its correctness depends on another property (ex. : int minX and int maxX, where minX must be lower or equal than maxX : to set them both from 20,30 to 40,60 setMaxX() must be called before setMinX() or the call will fail. And inversely to reset them to their previous value...
    ---------------------------
    Andrew:
    True, but you can cater for this by either having a setter method that will allow you to set both values simultaneously, or having a setter method that has a parameter to indicate whether the value should be validated or not.

    OK. But now that I wrote above that using simple getters/setters is much more complex that what I do, it will be hard to convince me to support multiple setters syntaxes... How to use reflection efficiently with them ?
    Andrew:
    Having the variables public means that you have no thread safety. In the case you mentioned, you could be changing both values, and until both have been set, you have invalid values. If another thread reads those values at that point, it will have invalid and unusable values.
    If you have a setter, you can ensure thread safety. If the one setter accepts both values, then you can ensure that no other thread can get the intermediate values. If you have a setter that has a parameter indicating that this is an intermediate value, you can set an internal boolean indicating that the values may not be read through the getter at present.

    No thread safety ? Right. But not less than the thread safety offered by HashMap or any array. It's up to the Settings user to make sure his code is thread-safe if he needs it. BTW, it would be very easy to make my example above thread-safe as any private Settings instance is a good candidate to be a monitor :

    ---------------------------
    Phil:Some properties are related to each other not for validation only, but because changing any of them may fire some action while all of them are used by the given action. Ex.: changing the IP Address or the listen port of your server could make it reset its listening process. But as both of those properties are used in the reset process, you probably won't initiate it automatically from any of the corresponding setters.
    ---------------------------
    Andrew:
    True, but this could be handled by having a setter with a "dontUpdateObservers" parameter.

    OK. But it's still based on "special" setters (see my comments above).
    ---------------------------
    Phil:As there is no central place where to group your properties, you need at least to document your class to make clear, among your numerous instance variables, which are properties and which are not.
    ---------------------------
    Andrew:

    What I meant is that you have less to document and you can do it in a simpler way :
    In the class which uses the Settings (MyClassWithSettings in the example above), you have just one getter and one setter to document, in just one sentence with a link to the MySettings doc. And to document MySettings, you just have a few public variables to document.
    Example of the typical javadoc for a getter :

    ---------------------------
    Phil:As the GUI writer, as you have no way to validate the properties as a whole, you'll need to write validation routines yourself, probably at the GUI level, which is bad practice, but also supposes that you get some deep understanding of the related class.
    ---------------------------
    Andrew:
    I think this is an argument for having getters and setters on some class that just handles properties

    OK, it confirms that we agree at least on the principle of centralizing properties in special container classes.
    Best,
    Phil.
    [ October 31, 2003: Message edited by: Philippe Maquet ]
    Philippe Maquet
    Bartender

    Joined: Jun 02, 2003
    Posts: 1872
    Hi Andrew,
    Do you agree with my last arguments ? It may be as short as one word of 3 characters , but your answer could help me close the discussion in my mind.
    Best,
    Phil.
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11503
        
      95

    Hi Phil,
    Originally posted by Philippe Maquet:
    Do you agree with my last arguments ? It may be as short as one word of 3 characters

    Non

    Originally posted by Philippe Maquet:
    I hesitated before doing so, but after having compared both techniques (a simple container of public variables (1) vs a container of private variables along with getters/setters (2)), I concluded that solution (1) offered many advantages :
  • When I implement a new Settings class, I save the time of writing one getter/setter pair per property.
  • As validation is better handled for the Settings object as a whole, the getters/setters would do nothing else than provide a public access to their corresponding private variable.
  • Accessing properties through getters/setters would make the reflection part of the job harder. Just think of the fact that Settings supports array properties for all native types and String. For them, I would need special getters/setters ...
  • In a Settings object, the convention used to identify properties is simple : there are all public fields, period. For instance, AbstractSettings stores a private prefix used to name properties. As it's private, it's automatically ignored. "public" acts as a "property-marker" and it's handy. If properties could be mixed with other instance variables at the same access level, I would need some other convention (based on the variale name ?), probably more complex to describe, remember, and follow.
  • I found that using reflection on public fields to support automatic two-way conversion on all native types, Strings and arrays of them was ... complex enough ! Sure Mark would agree with it.


  • Fair enough
  • Hmmm - maybe
  • Do you use reflection for this?
    Actually reflection can handle this very well, as long as you use standard "get" and "set" prefixes to your getters and setters. (If it didn't work, JavaBeans would be in trouble )
  • Hmmm, I don't think this is a reason for having public variables, it just happens to be the logical way you have used that feature.
  • I am not sure what the "reason" is in this argument


  • Originally posted by Philippe Maquet:
    [Using a singleton] would be quite restrictive because classes which must support multiple instances with different settings values could not use that singleton or static properties container. I have a multi-tables db design : it makes sense that each Table instance gets its own DBSettings instance (maybe different cache settings but ... for sure a different file name).

    Hmmm - interesting usage. You may have a point there, I may have to think about this some more.
    Originally posted by Philippe Maquet:
    No thread safety ? Right. But not less than the thread safety offered by HashMap or any array. It's up to the Settings user to make sure his code is thread-safe if he needs it.

    But that, in a way, is the point - it is up to the user to make sure his code is thread safe. Using a singleton (or multiton) you can ensure the settings will be thread safe no matter what the junior programmer does later.
    Originally posted by Philippe Maquet:
    Some properties are related to each other not for validation only, but because changing any of them may fire some action while all of them are used by the given action. Ex.: changing the IP Address or the listen port of your server could make it reset its listening process. But as both of those properties are used in the reset process, you probably won't initiate it automatically from any of the corresponding setters.
    Originally posted by Andrew Monkhouse:
    True, but this could be handled by having a setter with a "dontUpdateObservers" parameter.
    Originally posted by Philippe Maquet:
    OK. But it's still based on "special" setters (see my comments above).

    OK - argument accepted.
    Originally posted by Philippe Maquet:
    you have less to document and you can do it in a simpler way

    Yep - that is a good point
    ---
    OK, having argued this far, I should go back to my original comment, I think that global properties may be a valid candidate for having global variables.
    You have put forward good arguments for making the variables global, so I don't think that you should have a problem with this.
    Just for a slightly different perspective, I have just been looking in the JavaDoc. I can't think of any classes that have public modifiable fields, but many of them do have protected modifiable fields. Perhaps you should look at whether you do need public access to your variables, or whether protected access would work for you.
    Regards, Andrew
    Philippe Maquet
    Bartender

    Joined: Jun 02, 2003
    Posts: 1872
    Hi Andrew,
    Andrew:
    Originally posted by Philippe Maquet:
    Do you agree with my last arguments ? It may be as short as one word of 3 characters
    Non
    I didn't think of any possible translation in french coming from you.
    Anyway I just hoped a simple "Yes" reply to help us close this de facto private discussion.

    Andrew: (about array properties and/or getters/setters)
    3 Do you use reflection for this?
    Actually reflection can handle this very well, as long as you use standard "get" and "set" prefixes to your getters and setters. (If it didn't work, JavaBeans would be in trouble )

    Mmh... Do you suggest that I should use the beans package ? That I'm reinventing the wheel in some way ?
    I now wonder.
    But within my narrow settings context, isn't importing the beans package like using a big truck where a child's scooter would do the job ? I may have to think about this some more.
    Here is one side of the child's scooter (my AbstractSettings.getContents() method) :

    Isn't it just simple (and complex ) enough for the scope of our assignment ?
    Andrew:
    4. Hmmm, I don't think this is a reason for having public variables, it just happens to be the logical way you have used that feature.

    Good point : I confess it was not the reason, just a "side-effect" or "after-thought" argument.
    Now designing is a iterative process as coding is. And each time I find some "good reason for it" after design stage, I just take it as a heaven-gift !
    Andrew:
    OK, having argued this far, I should go back to my original comment, I think that global properties may be a valid candidate for having global variables.
    You have put forward good arguments for making the variables global, so I don't think that you should have a problem with this.

    As my first aim with this thread was building and testing my arguments (because of the "transgressed taboo"), I thank you for having come in this thread with opposite arguments.
    Andrew, if you weren't a moderator of this forum, we should invent you !
    All best,
    Phil.
    [ November 01, 2003: Message edited by: Philippe Maquet ]
    [ November 01, 2003: Message edited by: Philippe Maquet ]
    [ November 01, 2003: Message edited by: Jim Yingst ]
    Jim Yingst
    Wanderer
    Sheriff

    Joined: Jan 30, 2000
    Posts: 18671
    Phil, I edited your post because another annoying UBB feature is that if you have a really long line inside [ code ] tags, that forces the entire page to be really long, distorting the presentation of the other posts as well. So I removed the offending comment, which was about how UBB doesn't like "fields[i]". I put in a simple workaround in the post above; there's also a more subtle solution which I used for this post, but I'll let you figure that one out.


    "I'm not back." - Bill Harding, Twister
    Philippe Maquet
    Bartender

    Joined: Jun 02, 2003
    Posts: 1872
    I forgot it, but was my comment so offending ?
    Let's say then that I still need to get used to the subtle nice features of the UBB-code tag.
    I knew already that :
  • it happens sometimes that it swallows previous "quote" blocks (just when it feels hungry ?)
  • when reading some of my "for loops", it starts winking (OK, I may understand that)


  • and today I noticed the way it tries to interpret array indices ...
    What will be the next surprise ?
    I cannot resist :

    [/I]
    Anyway, thanks for the two workarounds.
    All best,
    Phil.
    [ November 01, 2003: Message edited by: Philippe Maquet ]
    Jim Yingst
    Wanderer
    Sheriff

    Joined: Jan 30, 2000
    Posts: 18671
    I forgot it, but was my comment so offending ?
    No. It was too long for one line, but normally I correct that by inserting line breaks. However in this case I could also correct the very problem you were commenting on, namely the [ i ] ndex - and once that correction was made, the comment itself served no further purpose.
    What will be the next surprise ?
    If I told you, it wouldn't be a surprise.
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11503
        
      95

    Hi Phil,
    I didn't think of any possible translation in french coming from you.


    Mmh... Do you suggest that I should use the beans package ?

    No, that was not my intent. I was only mentioning beans as an example that reflection can work even with private variables (but it requires getters and setters, which you don't want). The counter argument of course is that EJB primary key classes are not allowed to have private variables that are part of the key.
    Isn't [the code] just simple (and complex ) enough for the scope of our assignment ?


    As for the thread hijack by Jim :roll:

    ) = )
    [ = [
    (I know - this is way too much work for normal copying and pasting of code. But hopefully the new forum software will make this unnecessary.)
    That's also how I get to to write [code], [/code] in a single line when I am making comments to people about using code blocks.
    Regards, Andrew
     
    I agree. Here's the link: http://aspose.com/file-tools
     
    subject: Properties/Settings - a design question