IA 103

39 views
Skip to first unread message

mP

unread,
Jul 17, 2013, 11:23:35 PM7/17/13
to illegal...@googlegroups.com
Is it just me but all the complaints against java basically amount to laziness to type.

1/
There was an example base class that holds common properties. Sub classing is always done because were too lazy to make things more elegant. Today it might seem smart until a few months down the path, theres a big mess, because the base class has been used in logic etc to do stuff.

2/
Peter also was complaining about typing types and wanted the compiler to just know. Is this not lazyness again ? Too lazy to think and structure things properly so you hope it just works out and let the compiler guess. This of course works out until you need to refactor or change something and your in pain because there is no type info in the source. 

3/
There was also another related example about introducing a dependency on some salesforce class or interface(cant recall which). Personally i think its almost always wrong to depend on 3rd party intf in a general case. They should be hidden away and never become part of the main core system. Shouldnt this be hidden away by a layer of indirection ? Is this is not lazyness in adding an interface belonging to the system and behind the scenes theres a Saleforce impl ?

There were a few others, but i cant recalll them exactly, but im sure they were also products of basic laziness. Im not saying being lazy is wrong, im just trying to be fair in diagnosing the course and the effect.

Mark Derricutt

unread,
Jul 18, 2013, 12:05:40 AM7/18/13
to illegal...@googlegroups.com
Not quite, maybe…

1 - one of the problem I often have ( solved by mixins and/or extension methods, delegation foo, and will also be solved by JDK8's default methods ) is when theres shared logic between two or three "similar" classes that for what ever reason cannot share a common parent class. You end up writing a whole of delegation methods and duplicating stub logic over the place.

This then leads to the issue of any changes in that shared API, ripple out to any of the implementations offering stubs, which will make for extra pointless lines in a diff. Or, of those implementations are in separate artefacts, multiple diffs/commits/releases across all affected consumers - even if they don't need updating.

So not really laziness, but more just wanting to be tidy, or as you say - more elegant.

2 - I see this quite similar to the above, if I have a method that returns an Int and the type is specified everywhere, if I can that to a Long then I also have to write commit/diffs containing every reference being changed. If however those return types are inferred by the compiler than _can_ ( not always mind you ) end up with a cleaner diff/change set only changing the definition - all the usages are unchanged.

3 - I can't actually recall what we said then, I'll have to go and revisit that. Hiding it behind the core system is wise yes, unless for whatever reason it's actually causing a manifestation IN the core system. I believe this was more talking about the general expression problem, and actually ties into hiding it away. The problem is introduced when you have components A and B which are separate artefacts, and isolated from each other, and you now have component C that wants to use A and B to talk to D.  Sometimes it's more readable to consistently refer to the A and B objects with interface with D, but that can often mean that A and B need to implement an interface related to D so that they can be used. However, A and B have no reason of their own to know that D exists, so you really want to provide the implementation of D's interfaces for A and B, from the C module - enter type classes.



--
 
---
You received this message because you are subscribed to the Google Groups "illegalargument" group.
To unsubscribe from this group and stop receiving emails from it, send an email to illegalargume...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/illegalargument/2d748c33-31f2-4e17-b726-e2e17e198018%40googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

mP

unread,
Jul 18, 2013, 4:16:26 AM7/18/13
to illegal...@googlegroups.com


On Thursday, July 18, 2013 2:05:40 PM UTC+10, Mark Derricutt wrote:
Not quite, maybe…

1 - one of the problem I often have ( solved by mixins and/or extension methods, delegation foo, and will also be solved by JDK8's default methods ) is when theres shared logic between two or three "similar" classes that for what ever reason cannot share a common parent class. You end up writing a whole of delegation methods and duplicating stub logic over the place.

This then leads to the issue of any changes in that shared API, ripple out to any of the implementations offering stubs, which will make for extra pointless lines in a diff. Or, of those implementations are in separate artefacts, multiple diffs/commits/releases across all affected consumers - even if they don't need updating.


Im not going to pretend that Java has not got short comings, because it has. My reply was about being lazy knowing you have this limitation regarding lack of mixins and many other goodies and going with something that is crap, eg sub classing. We know this may lead to problems because adding or changing properties for an entity for example is a problem if the other entnties that share this parent dont want this chance.

 
So not really laziness, but more just wanting to be tidy, or as you say - more elegant.

2 - I see this quite similar to the above, if I have a method that returns an Int and the type is specified everywhere, if I can that to a Long then I also have to write commit/diffs containing every reference being changed. If however those return types are inferred by the compiler than _can_ ( not always mind you ) end up with a cleaner diff/change set only changing the definition - all the usages are unchanged.

Again i would call this lazy because you should be returning a nice value class that has an int property. If you had used the value type everything would be clearer. Your use case of now requiring a long is a much simpler change. Again i see laziness as the motivation for not creating this nice value class because making the return type int is so much easier. Theres no need to bother the compiler at all and your programs are a zillion times more type safe. I think im write again :)
 

3 - I can't actually recall what we said then, I'll have to go and revisit that. Hiding it behind the core system is wise yes, unless for whatever reason it's actually causing a manifestation IN the core system. I believe this was more talking about the general expression problem, and actually ties into hiding it away. The problem is introduced when you have components A and B which are separate artefacts, and isolated from each other, and you now have component C that wants to use A and B to talk to D.  Sometimes it's more readable to consistently refer to the A and B objects with interface with D, but that can often mean that A and B need to implement an interface related to D so that they can be used. However, A and B have no reason of their own to know that D exists, so you really want to provide the implementation of D's interfaces for A and B, from the C module - enter type classes.



Sorry, i appreciate the example in the podcast was grossly simplified, but in the reasoning sounded like laziness was a motivation. Im not sure how your example of A and B relates to the security bit so im a bit lost in how to respond to this :0.

Mark Derricutt

unread,
Jul 18, 2013, 8:10:42 AM7/18/13
to illegal...@googlegroups.com
On 18/07/2013, at 8:16 PM, mP <miroslav...@gmail.com> wrote:

Again i would call this lazy because you should be returning a nice value class that has an int property. If you had used the value type everything would be clearer. Your use case of now requiring a long is a much simpler change. Again i see laziness as the motivation for not creating this nice value class because making the return type int is so much easier. Theres no need to bother the compiler at all and your programs are a zillion times more type safe. I think im write again :)

Just going to reply to this piece at the moment, I don't see how returning a value object containing an int, and switching to a value object containing a long is any different to the initial problem - at some point you're going to need to extract that int/long out of the value object to use it.

One scenario where this very thing hit me awhile back, I was using an Integer as the type of an ID field, which worked fine for a long while, then we hit that magic point in time when we needed to change to a Long, most pieces of the code never look at IDs directly, some piece did but only used it as arguments and never assigned to variables, so inference there works naturally, however a few places assigned the id to a temporary variable for some reason, which meant declaring its type - which meant that needed to be patched as well, if it was type inferred we wouldn't need to, and we wouldn't be loosing any type-safety either - as that inferencing would then align up with the methods it was used as an argument in.

I don't see it as laziness, but wanting to minimise the amount of code that gets changed over time - surely the less code that changes, the less chances of bugs being introduced there are.
 

mP

unread,
Jul 18, 2013, 8:48:35 AM7/18/13
to illegal...@googlegroups.com


On Thursday, July 18, 2013 10:10:42 PM UTC+10, Mark Derricutt wrote:
On 18/07/2013, at 8:16 PM, mP <miroslav...@gmail.com> wrote:

Again i would call this lazy because you should be returning a nice value class that has an int property. If you had used the value type everything would be clearer. Your use case of now requiring a long is a much simpler change. Again i see laziness as the motivation for not creating this nice value class because making the return type int is so much easier. Theres no need to bother the compiler at all and your programs are a zillion times more type safe. I think im write again :)

Just going to reply to this piece at the moment, I don't see how returning a value object containing an int, and switching to a value object containing a long is any different to the initial problem - at some point you're going to need to extract that int/long out of the value object to use it.

I mentioned a value object because it saves the trouble of updating an ref to the old int if its scattered all over the place. I thought that was part of the problem being mentioned. Sure your right eventually you might or will write int or long to hold the primitive but still the boring task of fixing it when its used in other places just to forward it again is over.

mP

unread,
Jul 18, 2013, 11:33:26 PM7/18/13
to illegal...@googlegroups.com
I listened to part of the podcast again. 

Early at about 10:00, theres mention by Mark (i hope i remember that right) about Hibernate and its will sometimes save. This is again laziness. If Hibernate and its proxies never escape the Hibernate service layer to other layers you dont get this and many of the other Hibernate problems. Im not attempting to excuse Hibernate other ills, but if people didnt try and make models or value objects that do everything you wouldnt get these problems. What im saying if you only use Hibernate to persist by copying from your model to the Hibernate equivalent then stuff becomes simpler. Sure its more work, but theres less bullshit.

Im not trying to knock anyone, everyone is lazy me included, im just saying its not javas fault, its our fault for being lazy.

Richard Vowles

unread,
Jul 19, 2013, 12:00:19 AM7/19/13
to illegalargument
I don't agree on the Hibernate aspect. By using JPA and its variants with their implicit saves, it means you cannot use your domain model anywhere else. 

This is certifiably insane, and I cannot understand why we have let this go on for so long.

I was talking to another friend and they get around this problem by running Hibernate outside of transactions for everything, something fraught with the potential for accidents. The simple answer is just to have explicit saving. It makes things much more clear and much more elegant. 


--
 
---
You received this message because you are subscribed to the Google Groups "illegalargument" group.
To unsubscribe from this group and stop receiving emails from it, send an email to illegalargume...@googlegroups.com.

For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
---
Richard Vowles,
Grails, Groovy, Java, Javascript, AngularJS
Consistency is the last refuge of the unimaginative - Oscar Wilde
ph: +64275467747, google+:http://rvowl.es/UX8Bmq
podcast: http://www.illegalargument.com

mP

unread,
Jul 19, 2013, 3:43:50 AM7/19/13
to illegal...@googlegroups.com
@Richard

It sounds like your agreeing with me, trying to reuse your model by annotating it so it works with HIbernate or JPA or whatever your being lazy.

Moandji Ezana

unread,
Jul 19, 2013, 3:58:48 AM7/19/13
to illegalargument


On Jul 19, 2013 6:00 AM, "Richard Vowles" <ric...@bluetrainsoftware.com> wrote:

>The simple answer is just to have explicit saving. It makes things much more clear and much more elegant. 

Isn't that the default when using JPA?  Either way, I agree that implicit saving is extremely problematic.

Richard Vowles

unread,
Jul 19, 2013, 4:56:55 AM7/19/13
to illegalargument

No, implicit save happens if you are in a transaction, like it or not.

--
 
---
You received this message because you are subscribed to the Google Groups "illegalargument" group.
To unsubscribe from this group and stop receiving emails from it, send an email to illegalargume...@googlegroups.com.

mP

unread,
Jul 19, 2013, 5:34:59 AM7/19/13
to illegal...@googlegroups.com
So basically you agree that Hibernate should be using classes that never escape that layer. You copy from your model to the hibernate one do your stuff in an tx and thats it. Im saying you shoould never return anything touched, proxied or whatever by hibernate. No Hibernate/jpa/whatever annotations outside that layer. Only your service intf should ever be referenced by clients.

Mark Derricutt

unread,
Jul 19, 2013, 5:42:43 AM7/19/13
to illegal...@googlegroups.com
I would agree, and we do do that in -some- places, not all however. However, my complaint is that the boiler plate of maintaining that in Java is rather cumbersome, and changes in one layer would trigger many more onflowing changes.

Personally I'd rather Hibernate worked more like Scala's new Slick library - in that the entity objects are purely immutable value classes, not even anything on them MENTIONING the database.

Rob Lally

unread,
Jul 19, 2013, 12:11:42 PM7/19/13
to illegal...@googlegroups.com
So, say I'm writing a system to calculate someone's BMI and I want to perform a simple calculation on two values - height and weight - in your world I should create:

PatientDataTransferObject
HeightDataTransferObject
WeightDataTransferObject
PatientValue
HeightValue
WeightValue
BMIValue
PatientDataTransferObjectToPatientValueConverter
PatientValueToPatientDataTransferObjectConverter
HeightDataTransferObjectToHeightValueConverter
HeightValueToHeightDataTransferObjectConverter
WeightDataTransferObjectToWeightValueConverter
WeightValueToWeightDataTransferObjectConverter

And then reimplement all the arithmetic operations on HeightValue and WeightValue, but reimplement them repeatedly on each so that they're polymorphic.

And then unit test classes for all of it, and then since it is a reasonable chunk of code functional tests for it.

Because otherwise I'm being lazy?

Makes me pine for the good-old days when you could write some nice, concise EJB 1.0 code.

What I'm trying to get to is this, there are three really important facts about code

* code is read many, many times more than it is written
* defect count is always directly related to volume of code
* developers produce roughly the same volume of code per day irrespective of language

This leads to the inescapable fact that code that is both short AND transparent in purpose is the ideal we should be striving for. That's why Java (which I write every day) is inferior to Scala, Groovy, Clojure, Ruby and many, many other languages on these grounds - it is verbose and obfuscates intent behind boilerplate. 

Code also has to do what it is supposed to, with performance characteristics acceptable for your needs, and on these grounds Java is sometimes better than some of the other JVM languages.


Rob.



On 19 Jul 2013, at 02:34, mP <miroslav...@gmail.com> wrote:

So basically you agree that Hibernate should be using classes that never escape that layer. You copy from your model to the hibernate one do your stuff in an tx and thats it. Im saying you shoould never return anything touched, proxied or whatever by hibernate. No Hibernate/jpa/whatever annotations outside that layer. Only your service intf should ever be referenced by clients.


--
 
---
You received this message because you are subscribed to the Google Groups "illegalargument" group.
To unsubscribe from this group and stop receiving emails from it, send an email to illegalargume...@googlegroups.com.

mP

unread,
Jul 19, 2013, 8:12:44 PM7/19/13
to illegal...@googlegroups.com
I never said you should go crazy and create lots of classes. There was a clear logic behind it. 

- Your value type equals/hashcode should include all properties while Hibernate has different rules (eg skipping ids and using a selected business key).
- HIbernate is not really designed for immutability something you should do for your value types.

Before you jump and say that you dont want to load entire object graphs, maybe theres a message that you should have a smaller value type with the sub set that you want. Incomplete objects are dumb.

Im not saying my assertion is perfect, but your example is dumb and adds no benefit in anyway. My suggestion however does have some real benefits. Sure it has costs, but when some bullshit happens and you waste a few hours tracking it down, fixing that is significant more than the cost of doing it right the first time.

mP

unread,
Jul 19, 2013, 8:15:13 PM7/19/13
to illegal...@googlegroups.com
@Rob
I clearly said and showed the reason for the separate Hibernate layer and its mapped value objects. Your example is contrived and stupid. I forgot to mention the obvious dumb thing that your clients now require HIbernate if you add Hibernate annotations and other crap onto the value type. 

Mark Derricutt

unread,
Jul 19, 2013, 8:37:12 PM7/19/13
to illegal...@googlegroups.com
Well that's just where you use endomorphisms and the like right? ;p

Actually, this is -almost- what I'm actually wanting to do, but in a nicer manner - and where I see type classes coming in.

Say I already my patient management application, and have a Patient class in its own artifact, zero dependencies.

You've written your BMI calculation library and put it on maven central, but your API is generic, and does everything in the context of a WeightModel class, that has two fields: height and weight, both of which are your value classes contain value, and unit.

Now, I can integrate your library, and my schema object writing a PatientToWeightModelConverter class, and litter that throughout my code doing things like:

  val bmi = robsBmiTool.calculateBmi(new PatientToWeightModelConverter(patient))

and all is well, but that's not really all that readable, as the intent is blurred by including the converter in the code, to make this more readable we could have adapter your library to have a WeightModeller type class, which our wrapper class could become, then our call simply becomes

  val bmi = robsBmiTool.calculateBmi(patient)

and the intention of our code becomes much clearer, essentially we're saying "we want to extend the Patient class with a new interface WeightModeller, implemented via x, y, z" which is independent from our schema object, or your library. This means we don't have to update the schema objects with a new dependency, which would impact every user of that artifact.

Mark

Mark Derricutt

unread,
Jul 19, 2013, 8:40:17 PM7/19/13
to illegal...@googlegroups.com
Actually, just adding Hibernate annotations doesn't mean the client needs them.

If the annotations are not available on the class path then the JVM will (nicely, but also quite evilly) simply drop the annotation references from the loaded class and move on.

Makes for some really fun code when you're doing isAnnotationPresent() on a class the was loaded whose class loader didn't have the annotation classes visible and you spend hours trying to track down why their not being found :)

mP

unread,
Jul 20, 2013, 6:02:06 AM7/20/13
to illegal...@googlegroups.com
On Saturday, July 20, 2013 10:40:17 AM UTC+10, Mark Derricutt wrote:
Actually, just adding Hibernate annotations doesn't mean the client needs them.

If the annotations are not available on the class path then the JVM will (nicely, but also quite evilly) simply drop the annotation references from the loaded class and move on.

Makes for some really fun code when you're doing isAnnotationPresent() on a class the was loaded whose class loader didn't have the annotation classes visible and you spend hours trying to track down why their not being found :)


Exactly why ask for mysterious problems to pop out and smack you in the head, when your busy with something else.
 

mP

unread,
Jul 20, 2013, 6:05:03 AM7/20/13
to illegal...@googlegroups.com
Firstly the naming of those classes is wrong.

Theres no need to add "Value" to PatientValue or HeightValue, WeightValue or BMI. Im not sure what possible improvement PatientValue is over a Patient and HeightValue & WeightValue are different superfluous when compared to simpler Height & Weight. This is of course important because your Converters are not overly long for no particular reason. I have no idea why you would have a PatientDataTransferObject when you could just pass Patient. Seems pretty dumb.

Mark Derricutt

unread,
Jul 20, 2013, 6:05:25 AM7/20/13
to illegal...@googlegroups.com
On 20/07/2013, at 10:02 PM, mP <miroslav...@gmail.com> wrote:

Exactly why ask for mysterious problems to pop out and smack you in the head, when your busy with something else.

Er, you're changing your argument now - first you just said using the annotations would add the dependency, when I point out thats wrong you just side step that.

The problem with the annotations here that I had in the past was purely a hibernate layer only issue, but it was more an OSGi issue in that one of the bundles in the application wasn't importing the annotations so OSGi was tripping up the problems more than anything.

Mark Derricutt

unread,
Jul 20, 2013, 6:07:48 AM7/20/13
to illegal...@googlegroups.com
On 20/07/2013, at 10:05 PM, mP <miroslav...@gmail.com> wrote:

 I have no idea why you would have a PatientDataTransferObject when you could just pass Patient. Seems pretty dumb.

Well if Patient is the hibernate object, YOU don't want to pass that around :)

In my example cases, when crossing between two libraries you'd want some for of transfer object to bridge your object with the libraries interface.

Rob Lally

unread,
Jul 20, 2013, 2:18:44 PM7/20/13
to illegal...@googlegroups.com
My example is exactly what *you* described - having separate classes for persistence and for general purpose use. And since mixing concerns would be bad, you then need all the mapping classes. If I wanted to be silly I could have created interfaces for all the classes. I also kindly skipped out data-store classes and interfaces because, frankly, I got tired of typing it. Yes it is dumb. Yes that was my point.

And now with your demands for smaller value types you seem to want even more classes. I've already broken down all the numeric values into single classes, how much smaller should I make the classes? The PatientValue class only has two values and one derived value, how much smaller would you have that?

--
 
---
You received this message because you are subscribed to the Google Groups "illegalargument" group.
To unsubscribe from this group and stop receiving emails from it, send an email to illegalargume...@googlegroups.com.

Rob Lally

unread,
Jul 20, 2013, 2:20:59 PM7/20/13
to illegal...@googlegroups.com
The clients don't require hibernate. As per your request to separate concerns, the  *DataTransferObject classes have Hibernate annotations and  the *Value objects have no annotations. Since this was your plan, I'm not sure why you are surprised by that.

On 19 Jul 2013, at 17:15, mP <miroslav...@gmail.com> wrote:

@Rob
I clearly said and showed the reason for the separate Hibernate layer and its mapped value objects. Your example is contrived and stupid. I forgot to mention the obvious dumb thing that your clients now require HIbernate if you add Hibernate annotations and other crap onto the value type. 

--
 
---
You received this message because you are subscribed to the Google Groups "illegalargument" group.
To unsubscribe from this group and stop receiving emails from it, send an email to illegalargume...@googlegroups.com.

Rob Lally

unread,
Jul 20, 2013, 2:29:19 PM7/20/13
to illegal...@googlegroups.com
Separating the behaviour from the state here "robsBmiTool.calculateBmi(patient)" feels very un-object-oriented. I'm not opposed to that, I'm happy writing code in a functional style, but it doesn't fit very well with the whole purpose of the silly scheme - which was encapsulation. You've turned patient into a struct where all of the values need to be directly accessible.

At the end of the day, you've created another pretty complex scheme when what we really want it the calculation (mass / height ** 2).

Here's what I'm proposing: we have a patient class, it has annotations, it has two fields, it has a method to calculate BMI. We close our laptops and go out for a beer because our work here is done.


R.



--
 
---
You received this message because you are subscribed to the Google Groups "illegalargument" group.
To unsubscribe from this group and stop receiving emails from it, send an email to illegalargume...@googlegroups.com.

Rob Lally

unread,
Jul 20, 2013, 2:36:17 PM7/20/13
to illegal...@googlegroups.com
I assumed that since this whole thread started because you felt that developers who didn't want to type out the same things over and over again were lazy, that you'd value the explicitness.

If you put Value on the end of all Value classes then you would be communicating to everyone else that these were value objects.

As for the *Converter classes, you have to give them "clear" names because we're not lazy, and after all the reason we're going through all this dance, according to your argument, is that we might want to use some other transport/persistence mechanism in the future and then we'd end up with two sets of *Converter classes and we need to ensure they have different names.

You keep attacking this way of doing things, when it is *your* way, I just made clear how silly it was by typing it out. 

I think it is nuts, so look inside yourself if you don't like it. Write simple code, don't write code that is increasingly complex/complicated until you hit some personal complexity-barf-value where even you can't take it any more and stop. Strive for simplicity.


R.



--
 
---
You received this message because you are subscribed to the Google Groups "illegalargument" group.
To unsubscribe from this group and stop receiving emails from it, send an email to illegalargume...@googlegroups.com.

Rob Lally

unread,
Jul 20, 2013, 2:42:55 PM7/20/13
to illegal...@googlegroups.com
On 17 Jul 2013, at 21:05, Mark Derricutt <ma...@talios.com> wrote:

Not quite, maybe…

1 - one of the problem I often have ( solved by mixins and/or extension methods, delegation foo, and will also be solved by JDK8's default methods ) is when theres shared logic between two or three "similar" classes that for what ever reason cannot share a common parent class. You end up writing a whole of delegation methods and duplicating stub logic over the place.

This then leads to the issue of any changes in that shared API, ripple out to any of the implementations offering stubs, which will make for extra pointless lines in a diff. Or, of those implementations are in separate artefacts, multiple diffs/commits/releases across all affected consumers - even if they don't need updating.

So not really laziness, but more just wanting to be tidy, or as you say - more elegant.

2 - I see this quite similar to the above, if I have a method that returns an Int and the type is specified everywhere, if I can that to a Long then I also have to write commit/diffs containing every reference being changed. If however those return types are inferred by the compiler than _can_ ( not always mind you ) end up with a cleaner diff/change set only changing the definition - all the usages are unchanged.

I often find that gets weird. You regularly need to recompile downstream artifacts even though the code hasn't changed, because classes were generated based on the type inferred at compile time, which feels... wrong.

I guess that's one of the reasons I have more affinity with clojure these days, because on-the-fly compilation removes that need.


3 - I can't actually recall what we said then, I'll have to go and revisit that. Hiding it behind the core system is wise yes, unless for whatever reason it's actually causing a manifestation IN the core system. I believe this was more talking about the general expression problem, and actually ties into hiding it away. The problem is introduced when you have components A and B which are separate artefacts, and isolated from each other, and you now have component C that wants to use A and B to talk to D.  Sometimes it's more readable to consistently refer to the A and B objects with interface with D, but that can often mean that A and B need to implement an interface related to D so that they can be used. However, A and B have no reason of their own to know that D exists, so you really want to provide the implementation of D's interfaces for A and B, from the C module - enter type classes.



On 18/07/2013, at 3:23 PM, mP <miroslav...@gmail.com> wrote:

Is it just me but all the complaints against java basically amount to laziness to type.

1/
There was an example base class that holds common properties. Sub classing is always done because were too lazy to make things more elegant. Today it might seem smart until a few months down the path, theres a big mess, because the base class has been used in logic etc to do stuff.

2/
Peter also was complaining about typing types and wanted the compiler to just know. Is this not lazyness again ? Too lazy to think and structure things properly so you hope it just works out and let the compiler guess. This of course works out until you need to refactor or change something and your in pain because there is no type info in the source. 

3/
There was also another related example about introducing a dependency on some salesforce class or interface(cant recall which). Personally i think its almost always wrong to depend on 3rd party intf in a general case. They should be hidden away and never become part of the main core system. Shouldnt this be hidden away by a layer of indirection ? Is this is not lazyness in adding an interface belonging to the system and behind the scenes theres a Saleforce impl ?

There were a few others, but i cant recalll them exactly, but im sure they were also products of basic laziness. Im not saying being lazy is wrong, im just trying to be fair in diagnosing the course and the effect.


--
 
---
You received this message because you are subscribed to the Google Groups "illegalargument" group.
To unsubscribe from this group and stop receiving emails from it, send an email to illegalargume...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/illegalargument/2d748c33-31f2-4e17-b726-e2e17e198018%40googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 


--
 
---
You received this message because you are subscribed to the Google Groups "illegalargument" group.
To unsubscribe from this group and stop receiving emails from it, send an email to illegalargume...@googlegroups.com.

Mark Derricutt

unread,
Jul 20, 2013, 5:59:42 PM7/20/13
to illegal...@googlegroups.com
What I was meaning here, which may have not been clear is that in this project, at least in "my" mental variation of it, the situation is:

 - we've purchased and deployed mP's Patient Records System(tm), and we can't change that, without getting upstream/paid development.
 - we've found robsBmiCalculator on github/maven central and we wish to add BMI calculation/history for our patients, we can't change your code unless we fork the project, or submit a pull request and await a new release.
 - Neither mP's Patient System nor Robs BMI Calculator know about each other, and neither should they ever know about we other

If Robs BMI calculator takes in (weight,height) as two Double values then we're all good, we can just simply call calBmi(weight,height), however if for what ever reason Robs BMI calculator declares the interface BmiLike which has getHeight/getWeight accessors, we need to create a bridge between mP's Patient class and something that implements BmiLike, since we can't alter the upstream class.

In pseudo haskell, we could just declare an implement of BmiLike for Patient and move on:

instance BmiLike Patient p where
  getHeight = height p
  getWeight = weight p

and then just pass our patient instances to your function, which now implements the interface. Clojure provides a similar construct with its protocols, and scala has its type class pattern doing a similar thing. 

The whole specific example is somewhat contrived as I don't think you'd ever store a BMI directly on a Patient anyway, not as a direct value anyway, as height/weight changes over time any stored BMI reading as part of patient records would likely be stored as part of a timestamped diagnosis.

I don't really see this as violating encapsulation, but more expanding modularity, if we were in control of the whole system, we could keep the separation of concern/modularity from the -definition- side of things, and keep the OO mental model on the implementation side using extension methods, so you could still call patient.calculateBmi() and feel all OO hipster if you like.

After experimenting with Haskell and some other languages, that still do OO, but only... differently - in that they allow the operations on an class to be defined externally to the class itself is quite refreshing, and adds a hell of a lot of flexibility.

By having BMI calcuations in terms of BmiLike's, you're encapsulating the BMI logic around BmiLike's, the fact that one either alters Patient to implement BmiLike and ties that class to an implementation ( which may, or may not be desired ), or one extends Patient to implement the interface ONLY where its needed is not really the concern of the BMI calculator.

Rob Lally

unread,
Jul 20, 2013, 6:45:38 PM7/20/13
to illegal...@googlegroups.com
On 20 Jul 2013, at 14:59, Mark Derricutt <ma...@talios.com> wrote:

What I was meaning here, which may have not been clear is that in this project, at least in "my" mental variation of it, the situation is:

 - we've purchased and deployed mP's Patient Records System(tm), and we can't change that, without getting upstream/paid development.
 - we've found robsBmiCalculator on github/maven central and we wish to add BMI calculation/history for our patients, we can't change your code unless we fork the project, or submit a pull request and await a new release.
 - Neither mP's Patient System nor Robs BMI Calculator know about each other, and neither should they ever know about we other

If Robs BMI calculator takes in (weight,height) as two Double values then we're all good, we can just simply call calBmi(weight,height), however if for what ever reason Robs BMI calculator declares the interface BmiLike which has getHeight/getWeight accessors, we need to create a bridge between mP's Patient class and something that implements BmiLike, since we can't alter the upstream class.

In pseudo haskell, we could just declare an implement of BmiLike for Patient and move on:

You may be the first person in the history of the world to use the phrase "pseudo haskell". I salute you, sir, both for your creativity and your bravery (since I believe that writing anything haskellesque without provably correct type signatures will call down the wrath of the category-theory-ninjas).



instance BmiLike Patient p where
  getHeight = height p
  getWeight = weight p

and then just pass our patient instances to your function, which now implements the interface. Clojure provides a similar construct with its protocols, and scala has its type class pattern doing a similar thing. 

The whole specific example is somewhat contrived as I don't think you'd ever store a BMI directly on a Patient anyway, not as a direct value anyway, as height/weight changes over time any stored BMI reading as part of patient records would likely be stored as part of a timestamped diagnosis.

I don't really see this as violating encapsulation, but more expanding modularity, if we were in control of the whole system, we could keep the separation of concern/modularity from the -definition- side of things, and keep the OO mental model on the implementation side using extension methods, so you could still call patient.calculateBmi() and feel all OO hipster if you like.

After experimenting with Haskell and some other languages, that still do OO, but only... differently - in that they allow the operations on an class to be defined externally to the class itself is quite refreshing, and adds a hell of a lot of flexibility.

By having BMI calcuations in terms of BmiLike's, you're encapsulating the BMI logic around BmiLike's, the fact that one either alters Patient to implement BmiLike and ties that class to an implementation ( which may, or may not be desired ), or one extends Patient to implement the interface ONLY where its needed is not really the concern of the BMI calculator.

I get what you're saying, and I enjoy these sorts of intellectual exercises. And I think that it the ability to do this sort of thing, when needed, is incredibly valuable. It brings us back to the original point - Java as a language isn't very expressive, powerful or concise and many of us want to move to languages that are more powerful and expressive.

But, that said, software is all about trade-offs. Here you're working towards separation of concerns/modularity, but are giving up encapsulation, tell-don't-ask and violating the Law of Demeter. Not only that, with BmiLike you're requiring clients of the code to expose their internal organs to the world too.  I'm sure that there are times when that's the right choice, but most of the time when people create these sorts of systems it is because they are smart but bored by their environment and are trying to brighten up their day by over-engineering.

I've listened to all of your podcasts, and I'm pretty sure you're a smart guy. Use your intellect for good, not for evil!


R.



On 21/07/2013, at 6:29 AM, Rob Lally <rob....@gmail.com> wrote:

Separating the behaviour from the state here "robsBmiTool.calculateBmi(patient)" feels very un-object-oriented. I'm not opposed to that, I'm happy writing code in a functional style, but it doesn't fit very well with the whole purpose of the silly scheme - which was encapsulation. You've turned patient into a struct where all of the values need to be directly accessible.


--
 
---
You received this message because you are subscribed to the Google Groups "illegalargument" group.
To unsubscribe from this group and stop receiving emails from it, send an email to illegalargume...@googlegroups.com.

mP

unread,
Jul 20, 2013, 7:07:52 PM7/20/13
to illegal...@googlegroups.com


On Saturday, July 20, 2013 8:07:48 PM UTC+10, Mark Derricutt wrote:
On 20/07/2013, at 10:05 PM, mP <miroslav...@gmail.com> wrote:

 I have no idea why you would have a PatientDataTransferObject when you could just pass Patient. Seems pretty dumb.

Well if Patient is the hibernate object, YOU don't want to pass that around :)



Well thats crap naming. Your Hibernate class should be named HibernatePatient so theres no confusion. Lazy typing :) 

mP

unread,
Jul 20, 2013, 7:10:57 PM7/20/13
to illegal...@googlegroups.com


On Sunday, July 21, 2013 4:18:44 AM UTC+10, Rob Lally wrote:
My example is exactly what *you* described - having separate classes for persistence and for general purpose use. And since mixing concerns would be bad, you then need all the mapping classes. If I wanted to be silly I could have created interfaces for all the classes. I also kindly skipped out data-store classes and interfaces because, frankly, I got tired of typing it. Yes it is dumb. Yes that was my point.

And now with your demands for smaller value types you seem to want even more classes. I've already broken down all the numeric values into single classes, how much smaller should I make the classes? The PatientValue class only has two values and one derived value, how much smaller would you have that?


You completely missed half the motivation. Im also not sure where the Converters came from. I said there should be separate classes for Hibernate or JPA which points out theres a problem. This problem does not exist for the BIMIComputer or whatever. Whats more your naming is terrible, one cant really tell which are interfaces and which are classes just from the naming. You have invented contrived overly long terrible names.

mP

unread,
Jul 20, 2013, 7:12:38 PM7/20/13
to illegal...@googlegroups.com


On Sunday, July 21, 2013 4:20:59 AM UTC+10, Rob Lally wrote:
The clients don't require hibernate. As per your request to separate concerns, the  *DataTransferObject classes have Hibernate annotations and  the *Value objects have no annotations. Since this was your plan, I'm not sure why you are surprised by that.


You ignored the equals/hashcode issue i brought up which is directly influenced by Hibernate. A proper equals would include the id which is against general Hib recommendations.

Mark Derricutt

unread,
Jul 20, 2013, 9:56:16 PM7/20/13
to illegal...@googlegroups.com
On 21/07/2013, at 10:45 AM, Rob Lally <rob....@gmail.com> wrote:

I'm sure that there are times when that's the right choice, but most of the time when people create these sorts of systems it is because they are smart but bored by their environment and are trying to brighten up their day by over-engineering.

I think is the crux of what we've been discussing - and actually leads into part of the topic I'm wanting to raise/discuss on the next episode surrounding API design.

When using languages that ALLOW for more expressive designs - using closures/lambdas, type classes, extension methods etc. how does that affect HOW you approach designing an API. How do you decide when, or when NOT to use one, the other, or both mechanisms to provide your callers with the best usage of your API for THEIR needs.

Traditionally, an API seems to be a contract saying "this is how I think -everyone- should use my library", which invariably starts to fall down when people try to use your library/API in a way you didn't originally envisage.

One instance I can speak of here is in the first version of my HalBuilder API, internally I was using Google Guava, and at the API level I was also exposing Optional<...> values for things that may or not exist, and when using HalBuilder from a Java project this worked quite well, however when I tried using it from Kotlin - which supports the notional of nullable types, what that language saw was an Optional<String>? which says "this is an optional value containing an optional value", ideally in the Kotlin world you'd want to get just a String? back, similarly in Scala you'd be more inclined to getting a Option[String] back.

This also then transcends to writing an API in Scala/Kotlin that uses lambdas, Option's etc. - when using that from Java you can't use lambdas, at least not until JDK8 - and even then, JDK8 lambdas may not be interoperable with Scala functions - so you have to have that trade off of limiting your API to the lowest common denominator language, or structuring your API in a way that you can easily have a Scala/Kotlin wrapper API that provides the idiomatic wrappers needed.

So a lot of the "pain" expressed in the last episode comes from "the great awakening" of knowing how you could easily craft a solution in language x,w,z - but then translating that down to the legacy 'a' language you're dealing with.

Mark Derricutt

unread,
Jul 20, 2013, 9:59:47 PM7/20/13