Object configuration idioms

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
12 messages Options
Reply | Threaded
Open this post in threaded view
|

Object configuration idioms

Peter Uhnák
Hi,

are there any best practices/idioms in regards to object configuration/building?

Let's say I want to configure a TwitterClient that requires a username and a password that is stored in a separate object TwitterConfiguration

a) the basic approach (either separate sends or via cascade, that is not relevant here)

client := TwitterClient new.
client configuration username: 'XX'.
client configuration password: 'YY'.


b) #in: ...

It feels a bit more organized as it basically groups related operations together.
Also maybe avoiding demeter a bit?

client := TwitterClient new.
client configuration in: [ :config |
config username: 'XX'.
config password: 'YY'.
].

c) custom #somethingDo: method that basically does #in:

Again, feels more organized. Additionally one could perform some validation afterwards (to make sure the credentials are ok or whatever).

client := TwitterClient new.
client configurationDo: [ :config |
config username: 'XX'.
config password: 'YY'
].

Any thoughts on this?

Thanks,
Peter
Reply | Threaded
Open this post in threaded view
|

Re: Object configuration idioms

Sven Van Caekenberghe-2
Why not directly on TwitterClient ? That would be easiest for the user, then they do not need to know about TwitterConfiguration. Anyway, that is how I do it most often. The disadvantage is that TwitterClient might become a bit heavy, API wise, but you can delegate internally.

> On 11 Feb 2018, at 16:25, Peter Uhnák <[hidden email]> wrote:
>
> Hi,
>
> are there any best practices/idioms in regards to object configuration/building?
>
> Let's say I want to configure a TwitterClient that requires a username and a password that is stored in a separate object TwitterConfiguration
>
> a) the basic approach (either separate sends or via cascade, that is not relevant here)
>
> client := TwitterClient new.
> client configuration username: 'XX'.
> client configuration password: 'YY'.
>
>
> b) #in: ...
>
> It feels a bit more organized as it basically groups related operations together.
> Also maybe avoiding demeter a bit?
>
> client := TwitterClient new.
> client configuration in: [ :config |
> config username: 'XX'.
> config password: 'YY'.
> ].
>
> c) custom #somethingDo: method that basically does #in:
>
> Again, feels more organized. Additionally one could perform some validation afterwards (to make sure the credentials are ok or whatever).
>
> client := TwitterClient new.
> client configurationDo: [ :config |
> config username: 'XX'.
> config password: 'YY'
> ].
>
> Any thoughts on this?
>
> Thanks,
> Peter


Reply | Threaded
Open this post in threaded view
|

Re: Object configuration idioms

Christian Caldeiro
Maybe using directly TwitterClient, but using #doesNotUnderstand: to delegate there message sends to the configuration object(kind of a proxy pattern). That way the TwitterClient class doesn't became so heavy.

Christian



On Sun, Feb 11, 2018 at 1:35 PM, Sven Van Caekenberghe <[hidden email]> wrote:
Why not directly on TwitterClient ? That would be easiest for the user, then they do not need to know about TwitterConfiguration. Anyway, that is how I do it most often. The disadvantage is that TwitterClient might become a bit heavy, API wise, but you can delegate internally.

> On 11 Feb 2018, at 16:25, Peter Uhnák <[hidden email]> wrote:
>
> Hi,
>
> are there any best practices/idioms in regards to object configuration/building?
>
> Let's say I want to configure a TwitterClient that requires a username and a password that is stored in a separate object TwitterConfiguration
>
> a) the basic approach (either separate sends or via cascade, that is not relevant here)
>
> client := TwitterClient new.
> client configuration username: 'XX'.
> client configuration password: 'YY'.
>
>
> b) #in: ...
>
> It feels a bit more organized as it basically groups related operations together.
> Also maybe avoiding demeter a bit?
>
> client := TwitterClient new.
> client configuration in: [ :config |
>       config username: 'XX'.
>       config password: 'YY'.
> ].
>
> c) custom #somethingDo: method that basically does #in:
>
> Again, feels more organized. Additionally one could perform some validation afterwards (to make sure the credentials are ok or whatever).
>
> client := TwitterClient new.
> client configurationDo: [ :config |
>       config username: 'XX'.
>       config password: 'YY'
> ].
>
> Any thoughts on this?
>
> Thanks,
> Peter



Reply | Threaded
Open this post in threaded view
|

Re: Object configuration idioms

Stephane Ducasse-3
Arghhhhhh no magic please.
I got burned by too much DNU override.



On Sun, Feb 11, 2018 at 8:17 PM, Christian Caldeiro
<[hidden email]> wrote:

> Maybe using directly TwitterClient, but using #doesNotUnderstand: to
> delegate there message sends to the configuration object(kind of a proxy
> pattern). That way the TwitterClient class doesn't became so heavy.
>
> Christian
>
>
>
> On Sun, Feb 11, 2018 at 1:35 PM, Sven Van Caekenberghe <[hidden email]> wrote:
>>
>> Why not directly on TwitterClient ? That would be easiest for the user,
>> then they do not need to know about TwitterConfiguration. Anyway, that is
>> how I do it most often. The disadvantage is that TwitterClient might become
>> a bit heavy, API wise, but you can delegate internally.
>>
>> > On 11 Feb 2018, at 16:25, Peter Uhnák <[hidden email]> wrote:
>> >
>> > Hi,
>> >
>> > are there any best practices/idioms in regards to object
>> > configuration/building?
>> >
>> > Let's say I want to configure a TwitterClient that requires a username
>> > and a password that is stored in a separate object TwitterConfiguration
>> >
>> > a) the basic approach (either separate sends or via cascade, that is not
>> > relevant here)
>> >
>> > client := TwitterClient new.
>> > client configuration username: 'XX'.
>> > client configuration password: 'YY'.
>> >
>> >
>> > b) #in: ...
>> >
>> > It feels a bit more organized as it basically groups related operations
>> > together.
>> > Also maybe avoiding demeter a bit?
>> >
>> > client := TwitterClient new.
>> > client configuration in: [ :config |
>> >       config username: 'XX'.
>> >       config password: 'YY'.
>> > ].
>> >
>> > c) custom #somethingDo: method that basically does #in:
>> >
>> > Again, feels more organized. Additionally one could perform some
>> > validation afterwards (to make sure the credentials are ok or whatever).
>> >
>> > client := TwitterClient new.
>> > client configurationDo: [ :config |
>> >       config username: 'XX'.
>> >       config password: 'YY'
>> > ].
>> >
>> > Any thoughts on this?
>> >
>> > Thanks,
>> > Peter
>>
>>
>

Reply | Threaded
Open this post in threaded view
|

Re: Object configuration idioms

NorbertHartl


> Am 11.02.2018 um 21:34 schrieb Stephane Ducasse <[hidden email]>:
>
> Arghhhhhh no magic please.
> I got burned by too much DNU override.

+ magic number

Norbert

>
>
> On Sun, Feb 11, 2018 at 8:17 PM, Christian Caldeiro
> <[hidden email]> wrote:
>> Maybe using directly TwitterClient, but using #doesNotUnderstand: to
>> delegate there message sends to the configuration object(kind of a proxy
>> pattern). That way the TwitterClient class doesn't became so heavy.
>>
>> Christian
>>
>>
>>
>>> On Sun, Feb 11, 2018 at 1:35 PM, Sven Van Caekenberghe <[hidden email]> wrote:
>>>
>>> Why not directly on TwitterClient ? That would be easiest for the user,
>>> then they do not need to know about TwitterConfiguration. Anyway, that is
>>> how I do it most often. The disadvantage is that TwitterClient might become
>>> a bit heavy, API wise, but you can delegate internally.
>>>
>>>> On 11 Feb 2018, at 16:25, Peter Uhnák <[hidden email]> wrote:
>>>>
>>>> Hi,
>>>>
>>>> are there any best practices/idioms in regards to object
>>>> configuration/building?
>>>>
>>>> Let's say I want to configure a TwitterClient that requires a username
>>>> and a password that is stored in a separate object TwitterConfiguration
>>>>
>>>> a) the basic approach (either separate sends or via cascade, that is not
>>>> relevant here)
>>>>
>>>> client := TwitterClient new.
>>>> client configuration username: 'XX'.
>>>> client configuration password: 'YY'.
>>>>
>>>>
>>>> b) #in: ...
>>>>
>>>> It feels a bit more organized as it basically groups related operations
>>>> together.
>>>> Also maybe avoiding demeter a bit?
>>>>
>>>> client := TwitterClient new.
>>>> client configuration in: [ :config |
>>>>      config username: 'XX'.
>>>>      config password: 'YY'.
>>>> ].
>>>>
>>>> c) custom #somethingDo: method that basically does #in:
>>>>
>>>> Again, feels more organized. Additionally one could perform some
>>>> validation afterwards (to make sure the credentials are ok or whatever).
>>>>
>>>> client := TwitterClient new.
>>>> client configurationDo: [ :config |
>>>>      config username: 'XX'.
>>>>      config password: 'YY'
>>>> ].
>>>>
>>>> Any thoughts on this?
>>>>
>>>> Thanks,
>>>> Peter
>>>
>>>
>>

Reply | Threaded
Open this post in threaded view
|

Re: Object configuration idioms

Henrik-Nergaard
In reply to this post by Peter Uhnák
Hi Peter,

I would just fill in the configuration and have it give me the correct
client which uses the configuration instance.

=========================
| client |

client  := TwitterConfiguration new
  username: 'stuff';
  password: 'password1';
  port: '1234';
  useHttps;
  client.

TwitterConfiguration >> #client
    self perhapsValidateConfigurationHere.
   
    ^ self clientClassDependingOnConfiguration on: self

========================================

Best regards,
Henrik





--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Reply | Threaded
Open this post in threaded view
|

Re: Object configuration idioms

Christian Haider
In reply to this post by Peter Uhnák

Hi,

 

sorry to jump in here, but I think that this pattern is bad.

 

For your approach, you need to have setters on the configuration.

Do you really want to have methods to set the username and password from the outside – maybe even after you logged in?

 

To me an object like your configuration should be a value, which can be created but may never be modified after creation.

For this I would define a constructor:

 

TwitterConfiguration class>>username: aString password: anotherString

                | inst |

                inst := self new.

                inst initializeUsername: aString password: anotherString.

                ^inst

 

And an initializer:

 

TwitterConfiguration>> initializeUsername: aString password: anotherString

                username := aString.

password := anotherString

 

The two setters #username: and #password: should be deleted.

 

With TwitterClient at top, I would use constructors as well:

 

TwitterClient class>>username: aString password: anotherString

                | inst |

                inst := self new.

                inst initializeConfiguration: (TwitterConfiguration username: aString password: anotherString).

                ^inst

 

The nice thing about constructors is that the user knows what arguments are expected to get a valid object.

 

The initializers are intentionally prefixed with the cumbersome “initialize…” to indicate that they should not be confused with (multi-)setters.

(in VW, I additionally make these kinds of objects immutable to really make sure that the object cannot be modified after creation.)

 

So, please, think twice about using setters. They should be not used for initialization / configuration!

 

My 2 cents.

Cheers,

                Christian

 

 

 

Von: Pharo-users [mailto:[hidden email]] Im Auftrag von Peter Uhnák
Gesendet: Sonntag, 11. Februar 2018 16:26
An: Any question about pharo is welcome <[hidden email]>
Betreff: [Pharo-users] Object configuration idioms

 

Hi,

 

are there any best practices/idioms in regards to object configuration/building?

 

Let's say I want to configure a TwitterClient that requires a username and a password that is stored in a separate object TwitterConfiguration

 

a) the basic approach (either separate sends or via cascade, that is not relevant here)

 

client := TwitterClient new.

client configuration username: 'XX'.

client configuration password: 'YY'.

 

 

b) #in: ...

 

It feels a bit more organized as it basically groups related operations together.

Also maybe avoiding demeter a bit?

 

client := TwitterClient new.

client configuration in: [ :config |

             config username: 'XX'.

             config password: 'YY'.

].

 

c) custom #somethingDo: method that basically does #in:

 

Again, feels more organized. Additionally one could perform some validation afterwards (to make sure the credentials are ok or whatever).

 

client := TwitterClient new.

client configurationDo: [ :config |

             config username: 'XX'.

             config password: 'YY'

].

 

Any thoughts on this?

 

Thanks,

Peter

Reply | Threaded
Open this post in threaded view
|

Re: Object configuration idioms

Stephan Eggermont-3
Christian Haider
<[hidden email]> wrote:
> sorry to jump in here, but I think that this pattern is bad

The example with user and password is very atypical, as it has different
security requirements from most other code. See the recent post about using
volatile memory to avoid passwords and sessions being stored in the image

Stephan


Reply | Threaded
Open this post in threaded view
|

Re: Object configuration idioms

Sean P. DeNigris
Administrator
Stephan Eggermont-3 wrote
> See the recent post about using volatile memory to avoid passwords and
> sessions being stored in the image

Are you talking about the solution described in this mailing list thread
[1]:

>For my use case, since this api key is only sent to an ffi callout,
>my solution was to read the password from file into volatile memory so
>it disappears when the VM exits.  See this line....
>    externalVolatileSecret := ExternalAddress gcallocate: externalSize .

Is there also a blog post?

1.
http://forum.world.st/ANN-sentry-io-OSS-error-tracking-platform-SDK-tp5065977p5066084.html



-----
Cheers,
Sean
--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: Object configuration idioms

Stephan Eggermont-3
Sean P. DeNigris <[hidden email]> wrote:
>
> Are you talking about the solution described in this mailing list thread
 
Yes, that's the one. I would welcome a (blog)post about this

Stephan


Reply | Threaded
Open this post in threaded view
|

Re: Object configuration idioms

Stephane Ducasse-3
In reply to this post by Henrik-Nergaard
Nice design henrik. You made me think so this is good.

On Sun, Feb 11, 2018 at 11:27 PM, Henrik-Nergaard <[hidden email]> wrote:

> Hi Peter,
>
> I would just fill in the configuration and have it give me the correct
> client which uses the configuration instance.
>
> =========================
> | client |
>
> client  := TwitterConfiguration new
>   username: 'stuff';
>   password: 'password1';
>   port: '1234';
>   useHttps;
>   client.
>
> TwitterConfiguration >> #client
>     self perhapsValidateConfigurationHere.
>
>     ^ self clientClassDependingOnConfiguration on: self
>
> ========================================
>
> Best regards,
> Henrik
>
>
>
>
>
> --
> Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html
>

Reply | Threaded
Open this post in threaded view
|

Re: Object configuration idioms

Stephane Ducasse-3
In reply to this post by Christian Haider
Nice discussion.
Thanks Christian.

On Mon, Feb 12, 2018 at 10:36 AM, Christian Haider
<[hidden email]> wrote:

> Hi,
>
>
>
> sorry to jump in here, but I think that this pattern is bad.
>
>
>
> For your approach, you need to have setters on the configuration.
>
> Do you really want to have methods to set the username and password from the
> outside – maybe even after you logged in?
>
>
>
> To me an object like your configuration should be a value, which can be
> created but may never be modified after creation.
>
> For this I would define a constructor:
>
>
>
> TwitterConfiguration class>>username: aString password: anotherString
>
>                 | inst |
>
>                 inst := self new.
>
>                 inst initializeUsername: aString password: anotherString.
>
>                 ^inst
>
>
>
> And an initializer:
>
>
>
> TwitterConfiguration>> initializeUsername: aString password: anotherString
>
>                 username := aString.
>
> password := anotherString
>
>
>
> The two setters #username: and #password: should be deleted.
>
>
>
> With TwitterClient at top, I would use constructors as well:
>
>
>
> TwitterClient class>>username: aString password: anotherString
>
>                 | inst |
>
>                 inst := self new.
>
>                 inst initializeConfiguration: (TwitterConfiguration
> username: aString password: anotherString).
>
>                 ^inst
>
>
>
> The nice thing about constructors is that the user knows what arguments are
> expected to get a valid object.
>
>
>
> The initializers are intentionally prefixed with the cumbersome
> “initialize…” to indicate that they should not be confused with
> (multi-)setters.
>
> (in VW, I additionally make these kinds of objects immutable to really make
> sure that the object cannot be modified after creation.)
>
>
>
> So, please, think twice about using setters. They should be not used for
> initialization / configuration!
>
>
>
> My 2 cents.
>
> Cheers,
>
>                 Christian
>
>
>
>
>
>
>
> Von: Pharo-users [mailto:[hidden email]] Im Auftrag von
> Peter Uhnák
> Gesendet: Sonntag, 11. Februar 2018 16:26
> An: Any question about pharo is welcome <[hidden email]>
> Betreff: [Pharo-users] Object configuration idioms
>
>
>
> Hi,
>
>
>
> are there any best practices/idioms in regards to object
> configuration/building?
>
>
>
> Let's say I want to configure a TwitterClient that requires a username and a
> password that is stored in a separate object TwitterConfiguration
>
>
>
> a) the basic approach (either separate sends or via cascade, that is not
> relevant here)
>
>
>
> client := TwitterClient new.
>
> client configuration username: 'XX'.
>
> client configuration password: 'YY'.
>
>
>
>
>
> b) #in: ...
>
>
>
> It feels a bit more organized as it basically groups related operations
> together.
>
> Also maybe avoiding demeter a bit?
>
>
>
> client := TwitterClient new.
>
> client configuration in: [ :config |
>
>              config username: 'XX'.
>
>              config password: 'YY'.
>
> ].
>
>
>
> c) custom #somethingDo: method that basically does #in:
>
>
>
> Again, feels more organized. Additionally one could perform some validation
> afterwards (to make sure the credentials are ok or whatever).
>
>
>
> client := TwitterClient new.
>
> client configurationDo: [ :config |
>
>              config username: 'XX'.
>
>              config password: 'YY'
>
> ].
>
>
>
> Any thoughts on this?
>
>
>
> Thanks,
>
> Peter