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
to illegal...@googlegroups.com
On 21/07/2013, at 11:07 AM, mP <miroslav...@gmail.com> wrote:

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

Why include Hibernate in the name if its in the .hibernate package? Repeating Hibernate* on everything is not lazyness, but ugly.  Of course, sometimes unavoidable if you end up using .hibernate.Patient and .standard.Patient in the same source file ( unless you want to use FQN names everywhere ).

That can be resolved in languages like Scala that allow imports at any scope, and also allow renaming/aliasing of classes on import, so you could limit the usage of each.

And well - since IntelliJ auto-completes anything anyway, theres no more or less laziness in the physical typing - maybe for VIM users..

Mark Derricutt

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

On 21/07/2013, at 11:12 AM, mP <miroslav...@gmail.com> wrote:

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.

This weeks recommendations anyway. I remember a time they recommended ONLY checking the ID and nothing else!

mP

unread,
Jul 21, 2013, 5:04:47 AM7/21/13
to illegal...@googlegroups.com


On Sunday, July 21, 2013 11:59:47 AM UTC+10, Mark Derricutt wrote:
On 21/07/2013, at 11:07 AM, mP <miroslav...@gmail.com> wrote:

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

Why include Hibernate in the name if its in the .hibernate package? Repeating Hibernate* on everything is not lazyness, but ugly.  Of course, sometimes unavoidable if you end up using .hibernate.Patient and .standard.Patient in the same source file ( unless you want to use FQN names everywhere ).


First of all nobody types fq names in source, everybody uses imports. When both classes have to coexist in the same source file it becomes damn ugly and confusing. Theres no reason why one needs to omit the Hibernate portion, except laziness. Even Josh Bloch mentions this early in his effective java book, all simple class names should be unique. java.util.List & java.awt.List are a mistake for that very reason. IDEs are basically built for finding classes using their simple name.  Given a HibernatePerson exists only because of Person its good to show they are both related symatically even if at the language level there is no connection.  Really whats the trouble with typing HibernatePerson in what amounts to one or two busy classes ? Given HP should never escape the Hibernate layer if anyone spots a HibernateXXX anywhere else its a good aide at finding stray Hib components.
 
That can be resolved in languages like Scala that allow imports at any scope, and also allow renaming/aliasing of classes on import, so you could limit the usage of each.


No thats a solution looking for a problem, lazy programmers who dont want to type a few extra characters. Its these same types that forget to write nice comments or a meaningful toString or shock horror meaning exception messages.
 
And well - since IntelliJ auto-completes anything anyway, theres no more or less laziness in the physical typing - maybe for VIM users..

So why be lazy ? 

mP

unread,
Jul 21, 2013, 5:07:18 AM7/21/13
to illegal...@googlegroups.com
Exactly my point. The sensible thing for a typical value class is to include all its important fields and ignore the derived stuff. If you write up your equals/hascode to keep Hib happy your object equality is broken for the rest of the entire system. How bloody stupid & lazy. I dont really know or care what todays recommended e/h strategy is for Hib, the point is you should be isolating this peculiarities inside the layer were it belongs.

mP

unread,
Jul 21, 2013, 8:19:31 AM7/21/13
to illegal...@googlegroups.com


On Saturday, July 20, 2013 8:05:25 PM UTC+10, Mark Derricutt wrote:
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.


Not if they are kept for runtime. It doesnt really matter the point is Hibernate is polluting stuff outside its layer. Personally i always strive for doing stuff in that spirit so i never have to worry about even thinking about this maybe being a problem.

Maybe on a technical side im wrong, but overall my arguments are many times better than spurious reasoning to be "lazy" :)
 
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.

OSGI has nothing to do with it. Its about the footprint of the dependency. Clients of it should be simple as possible. Your worrying too much about technical small crap and missing the big picture.
 

Rob Lally

unread,
Jul 22, 2013, 2:42:16 PM7/22/13
to illegal...@googlegroups.com
I suspect that this is an intractable problem: unless all languages are equally capable of expressing and consuming all abstractions with equal facility then there's no way to write a cross-language API at anything other than the level of the lowest common denominator - AKA Java. 

Many of the Scala abstractions - such as implicits - were added in an attempt to facilitate idiomatic consumption of Java classes, and this hasn't worked out well even for Scala, so adding another JVM language into the mix and you're unlikely to be happy with the results.

I suspect that your choices have to be limited to Java plus at most one other language. Yes, there might be appealing libraries in another JVM language out there that you might want to include, but it probably is going to hurt more than it helps. 

Microsoft (whom I must disclose are my employers) did the best job I've seen of cross-language consumability with .NET's C#/VB/Managed C++ combination, but as soon as a radically different language - F# - was added to the mix, things got harder and consuming F# code from the others looks mighty odd.

As I think about it, it starts to feel like one of those chicken-and-egg situations, the base language - Java - can't blend the new abstractions because it isn't flexible or expressive enough. But if it could, then the language you'd want to blend features from would have no reason to exist, because the base language would have been equally effective. Which I suppose brings us to Lisp. Lisp aficionados will trumpet the notion that the language is flexible enough that you can shape it to your needs; something I'd largely agree with. One recent example of this is the core.async lib produced by the clojure team who have managed to implement a passable facsimile of Go's go routines as a *library* in clojure. The language is flexible enough to introduce a wholly new concurrency mechanism as a library. There are few languages that could boast this.

Of course this flexibility came at a price for Common Lisp; the language was so flexible that it didn't have any "natural" API, that lowest common denominator language API that any developer needs to get to grips with a project. I know that when I open a Java source file, the basic structure will be familiar to me, the API onto Java itself - the form and structure of code - is there to support me. All I need to do is to learn how it has been used, after years the structure and form becomes transparent and all that you can really see is the underlying domain logic.

I don't know where this was going, if I have a point, I guess is that there is no single API for a library, there are surfaces at a number of different levels that affect clients - language of choice, idioms and patterns followed, level of knowledge required to use the library, whether the library has a minimalist or comprehensive interface, whether you try to create a DSL or a more traditional structure, the dependencies that you drag in. Some of these are choices by the developers, some of these are expectations of the developers, and some are leaky abstractions. 

There's an old saying, and I don't know where it came from; "Everything software does for us, it also does to us". When you're designing an API, you need to keep that in mind, because since you're creating the software, "everything you do for users, you also do to users".


Rob.




--
 
---
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 22, 2013, 7:27:44 PM7/22/13
to illegal...@googlegroups.com
But VB.net is completely different to VB. The only reason VB.net and c# are such a good fit is they are basically the same thing with some keywords and syntax switched but at a lower level their asts etc are for all purposes the same.

Im sorry my solution to the problem with the hibernate usage which we have discussed i think is the only good one. its not a lang issue its about laziness. You can criticize java or whatever but the facts remain thge presented options just plain suck and let Hibernate bleed thru. My solution was the best by a country mile and should be the only solution, unless your lazy.

Mark Derricutt

unread,
Jul 22, 2013, 7:48:48 PM7/22/13
to illegal...@googlegroups.com
I don't think anyones really saying "checking hibernate hidden from everything else" is a bad thing. It's a good thing.

As for the laziness tho - yes, developers (good ones especially) are lazy - we want reusable abstractions so we don't have to write boiler plate code EVERYWHERE.

Also, if you think of Bob Martins SOLID stuff - a thing should have really only have ONE reason to change.  If you're changing all your view code, and multiple layers of different value objects because a Hibernate object changed you're doing something wrong. Which leads back to the original discussion of minimising changes in a diff or something - if you have the ability to reuse things, or have their types inferred and/or elided - there is inherently less reason for something to change. With  lots of value objects, and layers you bring in (the potential) for more changes - which may or not need additional changes.

It's all trade offs - and rants ;)

Rob Lally

unread,
Jul 22, 2013, 7:58:45 PM7/22/13
to illegal...@googlegroups.com
On 22 Jul 2013, at 16:27, mP <miroslav...@gmail.com> wrote:

But VB.net is completely different to VB. The only reason VB.net and c# are such a good fit is they are basically the same thing with some keywords and syntax switched but at a lower level their asts etc are for all purposes the same.

And managed C++? Is that also a homeomorphic with VB.NET?

PS The answer is "yes", since that was my point - only homeomorphic languages can interoperate without impedance mismatch.

Im sorry my solution to the problem with the hibernate usage which we have discussed i think is the only good one. its not a lang issue its about laziness. You can criticize java or whatever but the facts remain thge presented options just plain suck and let Hibernate bleed thru. My solution was the best by a country mile and should be the only solution, unless your lazy.

I kinda stopped responding to that thread since you didn't actually provide a solution only a inconsistent set of opinions and critiques.


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 22, 2013, 8:00:24 PM7/22/13
to illegal...@googlegroups.com
On 22 Jul 2013, at 16:48, Mark Derricutt <ma...@talios.com> wrote:

I don't think anyones really saying "checking hibernate hidden from everything else" is a bad thing. It's a good thing.

As for the laziness tho - yes, developers (good ones especially) are lazy - we want reusable abstractions so we don't have to write boiler plate code EVERYWHERE.

Also, if you think of Bob Martins SOLID stuff - a thing should have really only have ONE reason to change.  If you're changing all your view code, and multiple layers of different value objects because a Hibernate object changed you're doing something wrong. Which leads back to the original discussion of minimising changes in a diff or something - if you have the ability to reuse things, or have their types inferred and/or elided - there is inherently less reason for something to change. With  lots of value objects, and layers you bring in (the potential) for more changes - which may or not need additional changes.

To paraphrase "http://en.wikipedia.org/wiki/Indirection" : All problems in software can be solved by another layer of indirection, except too many layers of indirection.

R.


It's all trade offs - and rants ;)


On 23/07/2013, at 11:27 AM, mP <miroslav...@gmail.com> wrote:

Im sorry my solution to the problem with the hibernate usage which we have discussed i think is the only good one. its not a lang issue its about laziness. You can criticize java or whatever but the facts remain thge presented options just plain suck and let Hibernate bleed thru. My solution was the best by a country mile and should be the only solution, unless your lazy.




--
 
---
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 22, 2013, 10:45:58 PM7/22/13
to illegal...@googlegroups.com

As for the laziness tho - yes, developers (good ones especially) are lazy - we want reusable abstractions so we don't have to write boiler plate code EVERYWHERE.


There is a big difference between a programming god being lazy and writing an elegant solution and the typical programmer being lazy because well they are lazy. Its not really fair to lump both together, one sees a better way of doing stuff, the other just wants to get the shite off their plate and who cares what happens tomorrow. The later is the motivation i was referring in all my comments.

mP

unread,
Jul 22, 2013, 10:48:21 PM7/22/13
to illegal...@googlegroups.com


On Tuesday, July 23, 2013 9:58:45 AM UTC+10, Rob Lally wrote:
On 22 Jul 2013, at 16:27, mP <miroslav...@gmail.com> wrote:

But VB.net is completely different to VB. The only reason VB.net and c# are such a good fit is they are basically the same thing with some keywords and syntax switched but at a lower level their asts etc are for all purposes the same.

And managed C++? Is that also a homeomorphic with VB.NET?


Im not sure how that relates to laziness :) but of course languages are just sugar to help us get the job done.
 
PS The answer is "yes", since that was my point - only homeomorphic languages can interoperate without impedance mismatch.

Im sorry my solution to the problem with the hibernate usage which we have discussed i think is the only good one. its not a lang issue its about laziness. You can criticize java or whatever but the facts remain thge presented options just plain suck and let Hibernate bleed thru. My solution was the best by a country mile and should be the only solution, unless your lazy.

I kinda stopped responding to that thread since you didn't actually provide a solution only a inconsistent set of opinions and critiques.


Of course your reply was a joke, we all saw that but i was trying to be serious and so far none of the replies or attempted justifications were at all seriously better. 

mP

unread,
Jul 22, 2013, 10:53:13 PM7/22/13
to illegal...@googlegroups.com

I don't think anyones really saying "checking hibernate hidden from everything else" is a bad thing. It's a good thing.


As i said to Mark, its wrong to lump all lazy motivations. Theres a big difference between laziness that results in a good solution and the dude (tm) that just wants to piss off to the pub.
 
As for the laziness tho - yes, developers (good ones especially) are lazy - we want reusable abstractions so we don't have to write boiler plate code EVERYWHERE.

But none of the examples i commented on discussed in the podcast any improvement in any form. They are simply quick hacks that are nasty and crap. im sure the guys would acknowledge that, so lets be fair and honest when appraising the end result.

Also, if you think of Bob Martins SOLID stuff - a thing should have really only have ONE reason to change.  If you're changing all your view code, and multiple layers of different value objects because a Hibernate object changed you're doing something wrong. Which leads back to the original discussion of minimising changes in a diff or something - if you have the ability to reuse things, or have their types inferred and/or elided - there is inherently less reason for something to change. With  lots of value objects, and layers you bring in (the potential) for more changes - which may or not need additional changes.

To paraphrase "http://en.wikipedia.org/wiki/Indirection" : All problems in software can be solved by another layer of indirection, except too many layers of indirection.


Of course i agree a zillion layers is overkill and makes it overly complicated to comprehend any system, however my example about hibernate actually is a simplification. I think i have already justified this reasonably well previously so i wont bore readers with repetition. 

Mark Derricutt

unread,
Jul 22, 2013, 11:08:22 PM7/22/13
to illegal...@googlegroups.com
On 23/07/2013, at 2:53 PM, mP <miroslav...@gmail.com> wrote:

But none of the examples i commented on discussed in the podcast any improvement in any form. They are simply quick hacks that are nasty and crap. im sure the guys would acknowledge that, so lets be fair and honest when appraising the end result

Type inferencing and type classes are quick and nasty hacks? 

mP

unread,
Jul 22, 2013, 11:24:43 PM7/22/13
to illegal...@googlegroups.com

Type inferencing and type classes are quick and nasty hacks? 


Never said they were, but you cant just throw up some features and say thats the solution without some application.  TI doesnt solve anything its just an aide to save some typing. Sure you can use it to save typing but thats all it really does. Any other improvement requires a bit  more than that. im not sure how your going to use TC because you never quite gave more details. You could do many things with them, or you could do next to nothing.

Mark Derricutt

unread,
Jul 22, 2013, 11:27:08 PM7/22/13
to illegal...@googlegroups.com
On 23/07/2013, at 3:24 PM, mP <miroslav...@gmail.com> wrote:

im not sure how your going to use TC because you never quite gave more details. You could do many things with them, or you could do next to nothing.

Well I did in this thread - that was whole interacting with "robs BMI calculator" that took a BmiLike without having to modify the upstream Patient class, just providing "this is BmiLike for Patient" in the module/package/artifact that needed/wanted to do BMI stuff to Patients.

mP

unread,
Jul 22, 2013, 11:33:44 PM7/22/13
to illegal...@googlegroups.com
Sorry i must apologize i forgot about your comments. im quoting them below to help frame my response with some context.  I think i got myself ocnfused with Robs example.

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.

You cant type HibernatePaitent but you can type WeightModel ? Why bother with the Model suffix, it adds no meaning and is redundant, why not leave it at Wieght ?

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))

Why bother with a converter, why not simply get x or y or whatever and pass them as parameters. Its this type of crap that makes code horrible.

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)

You dont need to pass in paitent you could pass in paitent.height() and paitent.weight().

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.

You dont need any of those interface crap for that example three basic entities are enuff: Weight, Height & BmiCalculator. All that calculator this and interface hasWieght or whatever are nonsense and overengineer crap. 

Mark Derricutt

unread,
Jul 22, 2013, 11:54:16 PM7/22/13
to illegal...@googlegroups.com
On 23/07/2013, at 3:33 PM, mP <miroslav...@gmail.com> wrote:

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.

You cant type HibernatePaitent but you can type WeightModel ? Why bother with the Model suffix, it adds no meaning and is redundant, why not leave it at Wieght

You realise the point of this example was rooted in the fact that the BMI calculator, and the Patient class were written by independent people from my code - i.e. Rob's BMI code, your Patient code, and I couldn't change either.

I believe I did comment in one of the posts that I'd much rather just pass in weight/height as arguments, but sometimes upstream libraries don't do things just the way you want them to.

mP

unread,
Jul 23, 2013, 12:06:38 AM7/23/13
to illegal...@googlegroups.com
I never gave any paitent code involving converters. my example was extremely simple and i think its fair to say no way in appearance or function matches the funny bits given to us by Rob.

Well but in the case of the contrived example, extra nonsense has been introduced when there was a far simpler solution. Sure sometimes other libraries are crazy with weird idioms but in this case none of this is true. 

Mark Derricutt

unread,
Jul 23, 2013, 12:19:06 AM7/23/13
to illegal...@googlegroups.com
On 23/07/2013, at 4:06 PM, mP <miroslav...@gmail.com> wrote:

I never gave any paitent code involving converters.

No you didn't - and that's the crux behind whats known as "the expression problem", the way your code was designed was never envisioned to work with library X, Y, or Z. And just because I want to use X, Y, Z with data I'm getting from your system, doesn't mean I should have to change your system.

If I'm in a position to actually make that change, then by all means - a more elegant and useful solution could be done that way, but that may also involved way more releases for other projects which one may not wish to do at this point in time.

I do believe we're all arguing for the same thing, just from different angles in an endless loop, which I hope is tail recursive.

mP

unread,
Jul 23, 2013, 3:45:59 AM7/23/13
to illegal...@googlegroups.com
I gave you my solution simply introduce a layer to get the source height & weight from wherever. I skipped any attempt at this exercise because lets face it its boring and pointless.

My c64 didnt need tail recursion and its stack was only 256 bytes. Good abstractions dont need fancy modern languages, you can do just fine with old java. Sure these nice things are great but their absense is not an excuse to pretend its not possible and be lazy :)

Richard Vowles

unread,
Jul 23, 2013, 4:29:53 AM7/23/13
to illegalargument
The question is, is Scala the chocolate bar?



On Tue, Jul 23, 2013 at 7:45 PM, mP <miroslav...@gmail.com> wrote:
I gave you my solution simply introduce a layer to get the source height & weight from wherever. I skipped any attempt at this exercise because lets face it its boring and pointless.

My c64 didnt need tail recursion and its stack was only 256 bytes. Good abstractions dont need fancy modern languages, you can do just fine with old java. Sure these nice things are great but their absense is not an excuse to pretend its not possible and be lazy :)

--
 
---
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

Mark Derricutt

unread,
Jul 23, 2013, 6:07:45 AM7/23/13
to illegal...@googlegroups.com
On 23/07/2013, at 8:29 PM, Richard Vowles <ric...@bluetrainsoftware.com> wrote:

The question is, is Scala the chocolate bar?

If Scala's the chocolate bar, the type signatures are definitely the fluff that'll get stuck in your throat.

gak gak gak

Matthew Farwell

unread,
Jul 23, 2013, 10:26:22 AM7/23/13
to illegal...@googlegroups.com
If I don't read all of this discussion, am I being lazy?

Matthew Farwell.


2013/7/18 mP <miroslav...@gmail.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.

--
 
---
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 23, 2013, 12:29:10 PM7/23/13
to illegal...@googlegroups.com
On 23 Jul 2013, at 00:45, mP <miroslav...@gmail.com> wrote:

I gave you my solution simply introduce a layer to get the source height & weight from wherever. I skipped any attempt at this exercise because lets face it its boring and pointless.

My c64 didnt need tail recursion and its stack was only 256 bytes. Good abstractions dont need fancy modern languages, you can do just fine with old java. Sure these nice things are great but their absense is not an excuse to pretend its not possible and be lazy :)

The c64 effectively had tail recursion - in real code all jumps were written using GOTO which is ideal for recursive programming.

Your assertion seems to be that Java is the perfect language that cannot be improved upon, because any attempt to do so is hacky and lazy. I'm going to reiterate the section of one of my first messages that you studiously ignored, and then back out since your arguments consistently make no sense.



"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."



--
 
---
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 23, 2013, 11:43:41 PM7/23/13
to illegal...@googlegroups.com

The c64 effectively had tail recursion - in real code all jumps were written using GOTO which is ideal for recursive programming.


And the jvm uses lots of jmps internally. WHile tail recursion might typically be built on what are effectively gotos theres a difference.
 
Your assertion seems to be that Java is the perfect language that cannot be improved upon, because any attempt to do so is hacky and lazy. I'm going to reiterate the section of one of my first messages that you studiously ignored, and then back out since your arguments consistently make no sense.


My principal point was that not be lazy and create crappy code just because you need to type. Basically many examples mentioned in this thread are excused by the fact that java is verbose because it doesnt have this or that construct which is present in some other lang. The end result is people take the easist and laziest option that eventually bites someone in the future. I only mentioned java is adaquate because while it may be overly verbose good practices can still be performed. Sure lots of other languages help you out more with real options that doesnt change the fact the laziness.

mP

unread,
Jul 23, 2013, 11:48:07 PM7/23/13
to illegal...@googlegroups.com

"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

No its not. defects are also related to laziness. Many times someone somewhere has done a poor job in documenting something either in code or something like specs. Someone then gets it wrong and this leads to bugs. Misunderstand unreadable codes, specs that are incomplete, shitty docs that dont tell the truth about said api. Building on top of this often leads to the problems that you mention.
 
* developers produce roughly the same volume of code per day irrespective of language


All code is not equivalent. I can write a method that prints all the numbers from one to 1000 in one line or i can print the individual numbers one by one with their own print statements.
 
@Richard

Wheres Richard when you need him. 

Kerry Sainsbury

unread,
Jul 26, 2013, 2:22:53 PM7/26/13
to illegal...@googlegroups.com
@Richard

I've decided that '@Richard' is you are illustrating why I've come to strongly dislike overuse of annotations. Basically they can be read as "... and then some magic happens". Convention over Configuration becomes PITA when you have too many Conventions, and too much magic.

Also, for no good reason, apart from I feel like venting: Type inference removes clarity, Generics do not help with readability, and Hibernate is still a CROSS JOINing pile of garbage.

My favourite quote of mine is still: "Code must be *easily* understood. It lives a long time. Software Development is not a cleverness competition". I think there are a lot of developers who struggle to understand the last part especially.

Now leave me alone, I've got work to do!

Cheers
Kerry


--
 
---
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 26, 2013, 8:19:22 PM7/26/13
to illegal...@googlegroups.com

So you never use new style for loops, method chaining, autoboxing, or implicit toString conversions as anywhere? That's gonna be painful to work with.

Sent from an Android...

mP

unread,
Jul 26, 2013, 8:45:26 PM7/26/13
to illegal...@googlegroups.com
I hope you also put real toStrings on all your objects that are readable and worthwhile. It really sucks, when people dont try that little bit more and leave the default worthless Object.toString().

Kerry Sainsbury

unread,
Jul 26, 2013, 11:26:33 PM7/26/13
to illegal...@googlegroups.com

I don't follow your logic. I said *overuse* of generics, and meant at the application level. Sorry that I wasn't clear.

And no, I don't use implicit toString conversions anywhere that matters because you never really know what you're going to get, and (to repeat myself) I like things that are explicit.

Ooh, er.

Greg Amer

unread,
Jul 29, 2013, 3:58:26 AM7/29/13
to illegal...@googlegroups.com
I think, I am with you Kerry, on type inferencing, the lack of clarity overrides any benefit from not having to type the types. And all those people out there who are thinking of writing a response along the lines of "But you can put in the types where you need them", that isn't the problem. The problem is "Can you put in the types where I need them".




Mark Derricutt

unread,
Jul 29, 2013, 4:46:00 AM7/29/13
to illegal...@googlegroups.com
The ironic thing here is that, as a pusher of Clojure - all types are essentially inferred.





...and if you're thinking of replying that "no, the types are just pushed to the runtime" then ask yourself this - why does clojure have a "warn on reflection" mode that lets you know when it can't infer typing, and must resort to reflection. To be honest tho I'm not entirely sure WHERE this warning kicks in, it's possibly only on calls where you're doing java interop with (.someNativeMethod _) and it can't resolve the type there, but still :)
Reply all
Reply to author
Forward
0 new messages