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 <[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 |
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. |
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 >> >> > |
> 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 >>> >>> >> |
In reply to this post by Peter Uhnak
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 |
In reply to this post by Peter Uhnak
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 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
<[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 |
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 |
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 |
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 > |
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 |
Free forum by Nabble | Edit this page |