Re: Modelling in Clojure

2014-10-21 Thread Tom Oram
@Mike Hanley - Really great video, thanks for the link!

On Tuesday, 21 October 2014 15:26:35 UTC+1, Mike Haney wrote:
>
> I can't remember if someone posted this already, and the thread is too 
> long and I am too lazy to go back and check, so I apologize if it's already 
> been mentioned.
>
> Anyway, I found this talk very helpful when I started learning Clojure, 
> getting used to data-oriented thinking:
>
> http://www.infoq.com/presentations/Thinking-in-Data
>
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Modelling in Clojure

2014-10-21 Thread Tom Oram
Thanks for such a great reply James, it was exactly the answer I was hoping 
for. Also, the point about functions only checking the part of the map that 
are interested in is something which makes perfect sense but I'd not even 
considered. Having come from the idea that the data should be perfectly 
encapsulated and not contain anything unknown, I naturally wanted to ensure 
this couldn't happen. But now you've started me off on a whole new thought 
process of possibilities. Very interesting and thank you very much for your 
thoughts! 

On Tuesday, 21 October 2014 14:34:54 UTC+1, James Reeves wrote:
>
> I think there's should be a strong distinction between data that comes 
> from an external source, and data that comes from an internal source.
>
> External data should be verified as soon as it comes in. There should be a 
> thorough check at the top level that ensures everything is correct before 
> continuing. There's a reason why security checkpoints are carried out at 
> the borders of countries.
>
> Verifying internal data is a matter of program correctness. In an ideal 
> world, you'd make no mistakes and there would be no need to ever check. In 
> practice, it's sometimes helpful to add constraints that limit what can go 
> wrong.
>
> For example, let's take your send-message function:
>
> (defn send-message [customer message]
>   (send-email (:email customer) message))
>
> We could add preconditions that raise an error if things go wrong:
>
> (defn send-message [customer message]
>   {:pre [(email? (:email customer)) (string? message)]}
>   (send-email (:email customer) message))
>
> But in this case I'd be inclined to put the checks on the send-mail 
> function instead:
>
> (defn send-email [email message]
>   {:pre [(email? email) (string? message)]}
>   ...)
>
> If these preconditions are triggered, then something has gone wrong in 
> your code, but at least they limit the damage that can be done. 
> Preconditions like this might stop your app from flooding your SMTP server 
> with thousands of incorrectly formatted emails.
>
> With regards to whether you should test for additional fields in maps, I'd 
> say generally "no", because functions should only care about the part of 
> the map they're interested in. However, if you're iterating over the map, 
> or checking external data, then you probably do want to check.
>
> - James
>
>
>
> On 21 October 2014 13:17, Tom Oram > 
> wrote:
>
>> I think I've not got a much better idea of "data as the API" concept. 
>> What I'm still wandering is where do you do the validation of the data. For 
>> example, say a customer has a name, email and favourite colour. This could 
>> be represented as a map like so:
>>
>>  {:name "Tom", :email "t...@whatever.com ", :fav-colour :
>> blue}
>>
>>
>> So I'm guessing that an add customer usecase would be implemented through 
>> a function like so:
>>
>> (defn add-customer [customer]
>>   ; ...
>>   )
>>
>> The system has rules which state that a customer *must* have an email 
>> address and a name, fav colour is option though. My mind then says that, 
>> because add-customer is an API call (as in someone implementing a gui will 
>> want to make call to this function), then this
>> should perform some error checking that name and email exist in the map. 
>> Reasonable?
>>
>> Let's also say that maybe there's a *send-message* function, which takes 
>> a customer and a record, and sends the customer a message. This function is 
>> assumed to never be needed to be called externally from other functions in 
>> the system, so at this point do we skip the customer map validation, and 
>> assume that the API functions will protect against invalid customer maps.
>>
>> Example:
>>
>> (defn send-message [customer message]
>>   (send-email (:email customer) message)) ; no error checking because 
>> called from internal functions only
>>
>>
>> (defn add-customer [customer]
>>   (when (customer-is-valid customer) ; error checking because likely to 
>> be called externally
>> (add-to-database customer)
>> (send-message customer "Welcome")))
>>
>> Does that seem reasonable? (I hope I'm making sense!?)
>>
>> Also, what's the attitude towards adding entries into the data which are 
>> no expected, for example if I define my customer map with an :age. Is it 
>> the general attitude that adding an unknown field should cause an error, or 
>> should it just b

Re: Modelling in Clojure

2014-10-21 Thread Tom Oram
I think I've not got a much better idea of "data as the API" concept. What 
I'm still wandering is where do you do the validation of the data. For 
example, say a customer has a name, email and favourite colour. This could 
be represented as a map like so:

 {:name "Tom", :email "t...@whatever.com", :fav-colour :blue}


So I'm guessing that an add customer usecase would be implemented through a 
function like so:

(defn add-customer [customer]
  ; ...
  )

The system has rules which state that a customer *must* have an email 
address and a name, fav colour is option though. My mind then says that, 
because add-customer is an API call (as in someone implementing a gui will 
want to make call to this function), then this
should perform some error checking that name and email exist in the map. 
Reasonable?

Let's also say that maybe there's a *send-message* function, which takes a 
customer and a record, and sends the customer a message. This function is 
assumed to never be needed to be called externally from other functions in 
the system, so at this point do we skip the customer map validation, and 
assume that the API functions will protect against invalid customer maps.

Example:

(defn send-message [customer message]
  (send-email (:email customer) message)) ; no error checking because 
called from internal functions only


(defn add-customer [customer]
  (when (customer-is-valid customer) ; error checking because likely to be 
called externally
(add-to-database customer)
(send-message customer "Welcome")))

Does that seem reasonable? (I hope I'm making sense!?)

Also, what's the attitude towards adding entries into the data which are no 
expected, for example if I define my customer map with an :age. Is it the 
general attitude that adding an unknown field should cause an error, or 
should it just be accepted? (I'm guessing this may be a more application 
specific answer).

@Jirka: I'm afraid I don't have any answers to your questions (hopefully 
others will) but I very much  enjoyed reading the material you referenced. 
Thanks for the post!

On Thursday, 16 October 2014 22:19:32 UTC+1, Tom Oram wrote:
>
> Hello Clojure people,
>
> First up, apologies because this is going to be a long message. Howver, if 
> you do have the time to read and respond, then I would be extremely 
> grateful!
>
> Recently I've decided to give Clojure a proper go. Over the past year or 
> so I've paid it a bit of attention: I've read books all about how to use it 
> and I've spent a bit of time working through tutorials to create little web 
> apps and so on. I understand the language (although not to any great depth 
> yet), but I'm still unsure about the best approaches to actually working 
> with it.
>
> I've got many years of OOP experience, and I'm a big fan of principles 
> like SOLID and approaches like DDD. What I want to do now is, try and learn 
> how to build well designed models using Clojure, while using best 
> practices! I've started having a bit of a crack at it by building a simple 
> app, but I'm finding myself trying to transfer a lot of my existing OOP 
> techniques into Clojure. It's working, but I'm wandering if I'm overdoing 
> it or perhaps just not doing things "the Clojure way".
>
> So, my very first question is are there any good books or resources on 
> modelling, application architecture or best practices, using Clojure?
>
> Next up, maps vs records. I've read that the typical approach is to use 
> maps until the design starts to solidify and then you can move to records. 
> Is the the general attitude of Clojure developers or do some like to dive 
> straight in with records?
>
> The next question is encapsulation: I've taken the approach that I'm kind 
> of using namespaces like classes. If I want to create customer entity I 
> create a namespace for it, then add a "make" function to it which returns a 
> map of the right "shape".  I'm then shying away from accessing the map 
> directly, and rather doing it through other methods in the namespace which 
> take the instance as a parameter. E.g.
>
> (ns app.domain.customer)
>
>
> (defn make [name, email]
>   {:name name
>:email email})
>
>
> (defn get-name [customer]
>   (:name customer))
>
> Is this a reasonable approach? If not, what might be a better one?
>
> This leads on to safety and defensive programming. Using the approach 
> above, how much "type safety" is required? Obviously, in any API which is 
> going to be used by other programmers, you've got to handle bad inputs 
> well. But what is the Clojure approach in the "domain model"? Coming from

Re: Modelling in Clojure

2014-10-18 Thread Tom Oram
While this discussing has taken a slight tangent from my original question,
it's been a very interesting read. Thanks for all your thoughts everyone.
You guys rock!

On 18 October 2014 08:28, Mark Engelberg  wrote:

> Yeah, it's hard to deny the convenience of Clojure's keyword lookups and
> standard assoc mechanism for getting and setting stored values, but I think
> Bertrand Meyer's Uniform Access Principle reflects some pretty deep
> thinking about the kinds of complications that arise in maintaining large
> programs.  Although the Clojure community mostly rejects the Uniform Access
> Principle right now, as people start writing larger programs in Clojure,
> and need to maintain them for longer periods of time, it will be
> interesting to see if the pendulum swings back in favor of uniform access.
>
> It will be fun to have this conversation again in 5 years time.
>
> The good news is that if the community does start to see more value in
> uniform access, achieving that is just a few macros away.
>
> --Mark
>
> On Fri, Oct 17, 2014 at 10:49 PM, Mars0i  wrote:
>
>> On Thursday, October 16, 2014 11:53:42 PM UTC-5, puzzler wrote:
>>>
>>> In Clojure, non-computed fields are usually accessed directly by
>>> keyword, whereas computed fields require an actual API.  This difference in
>>> access style complicates things if you want to change which things are
>>> stored versus computed.
>>>
>>
>> This also means that you have to remember which data has a keyword
>> accessor and which uses a function.
>>
>> --
>> You received this message because you are subscribed to the Google
>> Groups "Clojure" group.
>> To post to this group, send email to clojure@googlegroups.com
>> Note that posts from new members are moderated - please be patient with
>> your first post.
>> To unsubscribe from this group, send email to
>> clojure+unsubscr...@googlegroups.com
>> For more options, visit this group at
>> http://groups.google.com/group/clojure?hl=en
>> ---
>> You received this message because you are subscribed to the Google Groups
>> "Clojure" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to clojure+unsubscr...@googlegroups.com.
>> For more options, visit https://groups.google.com/d/optout.
>>
>
>  --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with
> your first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to a topic in the
> Google Groups "Clojure" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/clojure/v03o5MWys9E/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> clojure+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Modelling in Clojure

2014-10-17 Thread Tom Oram
Oh also, can anyone recommend a really well designed OS application I can 
take a look at and study the code?

On Thursday, 16 October 2014 22:19:32 UTC+1, Tom Oram wrote:
>
> Hello Clojure people,
>
> First up, apologies because this is going to be a long message. Howver, if 
> you do have the time to read and respond, then I would be extremely 
> grateful!
>
> Recently I've decided to give Clojure a proper go. Over the past year or 
> so I've paid it a bit of attention: I've read books all about how to use it 
> and I've spent a bit of time working through tutorials to create little web 
> apps and so on. I understand the language (although not to any great depth 
> yet), but I'm still unsure about the best approaches to actually working 
> with it.
>
> I've got many years of OOP experience, and I'm a big fan of principles 
> like SOLID and approaches like DDD. What I want to do now is, try and learn 
> how to build well designed models using Clojure, while using best 
> practices! I've started having a bit of a crack at it by building a simple 
> app, but I'm finding myself trying to transfer a lot of my existing OOP 
> techniques into Clojure. It's working, but I'm wandering if I'm overdoing 
> it or perhaps just not doing things "the Clojure way".
>
> So, my very first question is are there any good books or resources on 
> modelling, application architecture or best practices, using Clojure?
>
> Next up, maps vs records. I've read that the typical approach is to use 
> maps until the design starts to solidify and then you can move to records. 
> Is the the general attitude of Clojure developers or do some like to dive 
> straight in with records?
>
> The next question is encapsulation: I've taken the approach that I'm kind 
> of using namespaces like classes. If I want to create customer entity I 
> create a namespace for it, then add a "make" function to it which returns a 
> map of the right "shape".  I'm then shying away from accessing the map 
> directly, and rather doing it through other methods in the namespace which 
> take the instance as a parameter. E.g.
>
> (ns app.domain.customer)
>
>
> (defn make [name, email]
>   {:name name
>:email email})
>
>
> (defn get-name [customer]
>   (:name customer))
>
> Is this a reasonable approach? If not, what might be a better one?
>
> This leads on to safety and defensive programming. Using the approach 
> above, how much "type safety" is required? Obviously, in any API which is 
> going to be used by other programmers, you've got to handle bad inputs 
> well. But what is the Clojure approach in the "domain model"? Coming from 
> the DDD mindset, where models are designed to be un-breakable, part of me 
> wants to use records for all entities and typehint for them everywhere. 
> However, I wander if the Clojure way is more about rigorous testing to make 
> sure the wrong values don't get put in in the first place? Also, what about 
> libraries like https://github.com/Prismatic/schema, this could be used in 
> :pre conditions to be more explicit, is that a common thing?
>
> Next up, how far do you go with creating "types" vs using primitives? 
> Again, referring back to DDD, both the email and the name in the example 
> above are suitable candidates for value objects. In Clojure, would you 
> consider hiding the data behind a set of specialised functions to create, 
> access and use it? Or would you just pass the primitive 
> string/map/vector/whatever about and work on it directly? Example:
>
>
> ; Given
> (defn make-customer [name email]
>  {:name name, :email email})
>  
> ; Examples
>  
> (def customer1 (make-customer "Tom" "em...@address.com"))
>  
> ; vs...
>  
> (defn make-name [name] name)
>  
> (defn make-email [email] email)
>  
> (def customer2
>  (make-customer (make-name "Tom")
>  (make-email "em...@address.com")))
>
>
>
> I think that's all I want to ask about now. I do have other questions 
> about dependency inversions, but I'll leave that for another time. If 
> you've read this far then thank you very very much! Also,I know that no one 
> really wants to just sit and read though random peoples code, but, if you 
> are interested in my (very very early stages) experimental project, then 
> I've put in on https://github.com/tomphp/clojure-cocktails - any 
> comments, critiques, PRs or questions would be really great!
>
> Thanks you so much for your times and I look forward to any thoughts or 
> suggestions!
> Tom
>

-- 
You rec

Re: Modelling in Clojure

2014-10-17 Thread Tom Oram
Wow! Thanks for all the replies everyone!

I had a suspicion that the general response would be that I was thinking 
too much in terms of OOP. I'm going to try and go more with the approach 
suggested in the replies (it's a mental struggle more than a technical one 
because I've definitely trained my brain to think in a particular way).

"The data is the API" seems to be a very strong point here. Also this 
comment from puzzler was very helpful:

"In Clojure, non-computed fields are usually accessed directly by keyword, 
whereas computed fields require an actual API."

Again, are there any suggested best practices resources available?

Thanks again everyone!

On Thursday, 16 October 2014 22:19:32 UTC+1, Tom Oram wrote:
>
> Hello Clojure people,
>
> First up, apologies because this is going to be a long message. Howver, if 
> you do have the time to read and respond, then I would be extremely 
> grateful!
>
> Recently I've decided to give Clojure a proper go. Over the past year or 
> so I've paid it a bit of attention: I've read books all about how to use it 
> and I've spent a bit of time working through tutorials to create little web 
> apps and so on. I understand the language (although not to any great depth 
> yet), but I'm still unsure about the best approaches to actually working 
> with it.
>
> I've got many years of OOP experience, and I'm a big fan of principles 
> like SOLID and approaches like DDD. What I want to do now is, try and learn 
> how to build well designed models using Clojure, while using best 
> practices! I've started having a bit of a crack at it by building a simple 
> app, but I'm finding myself trying to transfer a lot of my existing OOP 
> techniques into Clojure. It's working, but I'm wandering if I'm overdoing 
> it or perhaps just not doing things "the Clojure way".
>
> So, my very first question is are there any good books or resources on 
> modelling, application architecture or best practices, using Clojure?
>
> Next up, maps vs records. I've read that the typical approach is to use 
> maps until the design starts to solidify and then you can move to records. 
> Is the the general attitude of Clojure developers or do some like to dive 
> straight in with records?
>
> The next question is encapsulation: I've taken the approach that I'm kind 
> of using namespaces like classes. If I want to create customer entity I 
> create a namespace for it, then add a "make" function to it which returns a 
> map of the right "shape".  I'm then shying away from accessing the map 
> directly, and rather doing it through other methods in the namespace which 
> take the instance as a parameter. E.g.
>
> (ns app.domain.customer)
>
>
> (defn make [name, email]
>   {:name name
>:email email})
>
>
> (defn get-name [customer]
>   (:name customer))
>
> Is this a reasonable approach? If not, what might be a better one?
>
> This leads on to safety and defensive programming. Using the approach 
> above, how much "type safety" is required? Obviously, in any API which is 
> going to be used by other programmers, you've got to handle bad inputs 
> well. But what is the Clojure approach in the "domain model"? Coming from 
> the DDD mindset, where models are designed to be un-breakable, part of me 
> wants to use records for all entities and typehint for them everywhere. 
> However, I wander if the Clojure way is more about rigorous testing to make 
> sure the wrong values don't get put in in the first place? Also, what about 
> libraries like https://github.com/Prismatic/schema, this could be used in 
> :pre conditions to be more explicit, is that a common thing?
>
> Next up, how far do you go with creating "types" vs using primitives? 
> Again, referring back to DDD, both the email and the name in the example 
> above are suitable candidates for value objects. In Clojure, would you 
> consider hiding the data behind a set of specialised functions to create, 
> access and use it? Or would you just pass the primitive 
> string/map/vector/whatever about and work on it directly? Example:
>
>
> ; Given
> (defn make-customer [name email]
>  {:name name, :email email})
>  
> ; Examples
>  
> (def customer1 (make-customer "Tom" "em...@address.com"))
>  
> ; vs...
>  
> (defn make-name [name] name)
>  
> (defn make-email [email] email)
>  
> (def customer2
>  (make-customer (make-name "Tom")
>  (make-email "em...@address.com")))
>
>
>
> I think that's all I want to ask about now. I do have other questions 
> abo

Modelling in Clojure

2014-10-16 Thread Tom Oram
Hello Clojure people,

First up, apologies because this is going to be a long message. Howver, if 
you do have the time to read and respond, then I would be extremely 
grateful!

Recently I've decided to give Clojure a proper go. Over the past year or so 
I've paid it a bit of attention: I've read books all about how to use it 
and I've spent a bit of time working through tutorials to create little web 
apps and so on. I understand the language (although not to any great depth 
yet), but I'm still unsure about the best approaches to actually working 
with it.

I've got many years of OOP experience, and I'm a big fan of principles like 
SOLID and approaches like DDD. What I want to do now is, try and learn how 
to build well designed models using Clojure, while using best practices! 
I've started having a bit of a crack at it by building a simple app, but 
I'm finding myself trying to transfer a lot of my existing OOP techniques 
into Clojure. It's working, but I'm wandering if I'm overdoing it or 
perhaps just not doing things "the Clojure way".

So, my very first question is are there any good books or resources on 
modelling, application architecture or best practices, using Clojure?

Next up, maps vs records. I've read that the typical approach is to use 
maps until the design starts to solidify and then you can move to records. 
Is the the general attitude of Clojure developers or do some like to dive 
straight in with records?

The next question is encapsulation: I've taken the approach that I'm kind 
of using namespaces like classes. If I want to create customer entity I 
create a namespace for it, then add a "make" function to it which returns a 
map of the right "shape".  I'm then shying away from accessing the map 
directly, and rather doing it through other methods in the namespace which 
take the instance as a parameter. E.g.

(ns app.domain.customer)


(defn make [name, email]
  {:name name
   :email email})


(defn get-name [customer]
  (:name customer))

Is this a reasonable approach? If not, what might be a better one?

This leads on to safety and defensive programming. Using the approach 
above, how much "type safety" is required? Obviously, in any API which is 
going to be used by other programmers, you've got to handle bad inputs 
well. But what is the Clojure approach in the "domain model"? Coming from 
the DDD mindset, where models are designed to be un-breakable, part of me 
wants to use records for all entities and typehint for them everywhere. 
However, I wander if the Clojure way is more about rigorous testing to make 
sure the wrong values don't get put in in the first place? Also, what about 
libraries like https://github.com/Prismatic/schema, this could be used in 
:pre conditions to be more explicit, is that a common thing?

Next up, how far do you go with creating "types" vs using primitives? 
Again, referring back to DDD, both the email and the name in the example 
above are suitable candidates for value objects. In Clojure, would you 
consider hiding the data behind a set of specialised functions to create, 
access and use it? Or would you just pass the primitive 
string/map/vector/whatever about and work on it directly? Example:


; Given
(defn make-customer [name email]
 {:name name, :email email})
 
; Examples
 
(def customer1 (make-customer "Tom" "em...@address.com"))
 
; vs...
 
(defn make-name [name] name)
 
(defn make-email [email] email)
 
(def customer2
 (make-customer (make-name "Tom")
 (make-email "em...@address.com")))



I think that's all I want to ask about now. I do have other questions about 
dependency inversions, but I'll leave that for another time. If you've read 
this far then thank you very very much! Also,I know that no one really 
wants to just sit and read though random peoples code, but, if you are 
interested in my (very very early stages) experimental project, then I've 
put in on https://github.com/tomphp/clojure-cocktails - any comments, 
critiques, PRs or questions would be really great!

Thanks you so much for your times and I look forward to any thoughts or 
suggestions!
Tom

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.