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
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 <i.uhnak@gmail.com> 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
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 <sven@stfx.eu> 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 <i.uhnak@gmail.com> 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
Arghhhhhh no magic please. I got burned by too much DNU override. On Sun, Feb 11, 2018 at 8:17 PM, Christian Caldeiro <christian.caldeiro@gmail.com> 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 <sven@stfx.eu> 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 <i.uhnak@gmail.com> 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
Am 11.02.2018 um 21:34 schrieb Stephane Ducasse <stepharo.self@gmail.com>:
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 <christian.caldeiro@gmail.com> 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 <sven@stfx.eu> 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 <i.uhnak@gmail.com> 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
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
Nice design henrik. You made me think so this is good. On Sun, Feb 11, 2018 at 11:27 PM, Henrik-Nergaard <draagren@outlook.com> 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
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:pharo-users-bounces@lists.pharo.org] Im Auftrag von Peter Uhnák Gesendet: Sonntag, 11. Februar 2018 16:26 An: Any question about pharo is welcome <pharo-users@lists.pharo.org> 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
Christian Haider <christian.haider@smalltalked-visuals.com> 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
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-tp506597... ----- Cheers, Sean -- Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html
Nice discussion. Thanks Christian. On Mon, Feb 12, 2018 at 10:36 AM, Christian Haider <christian.haider@smalltalked-visuals.com> 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:pharo-users-bounces@lists.pharo.org] Im Auftrag von Peter Uhnák Gesendet: Sonntag, 11. Februar 2018 16:26 An: Any question about pharo is welcome <pharo-users@lists.pharo.org> 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
participants (9)
-
Christian Caldeiro -
Christian Haider -
Henrik-Nergaard -
Norbert Hartl -
Peter Uhnák -
Sean P. DeNigris -
Stephan Eggermont -
Stephane Ducasse -
Sven Van Caekenberghe