On 12 Mar 2010, at 02:49, Jeff Schnitzer wrote:

On Thu, Mar 11, 2010 at 4:59 AM, John Patterson <[email protected]> wrote:

Well then, where are your examples? I responded to the "edge cases" you
asked about with a simple example.  Now its your turn to show me how
Objectify would code the example I asked about.

I can see you are proud of your OR implementation.

I'm not going to respond to a feature by feature comparison; clearly
Twig has more features than Objectify, and while you're still missing
several critical features necessary to build real-world applications
today (2nd level caching, schema migration tools, batch gets) I'm sure
you will eventually add them.

Perhaps you should read the docs... caching is trivial to add and is in fact one of the examples in the docs.

Twig actually has probably the best schema migration available on GAE with its "versioned types". You can actually continue running an app while you upgrade a single type and process the data in a separate version.


I'm still pretty comfortable making my claim that in a Real World
application (not contrived examples designed to highlight Twig's
features), the corresponding code in Objectify will be more elegant.
Despite your ranting about the evils of Key, I (and quite a few
others) have developed sophisticated applications with Objectify and
we like the result.

Glad to hear you are comfortable. I am still waiting to see any evidence of this claim at all. I have given examples.

I'll grant you that some of what are annotations in Twig might result
in code in Objectify.  This isn't necessarily a bad thing.  Taken to
an extreme, JDO has created an annotation for nearly everything,
producing a nasty initial learning curve.  I'm of the opinion that
annotations are code just like anything else, so I think it's fair to
let the user type a little more when they are running a query - as
long as the code reads well.

I don't think Twig has any more annotations than Objectify?

I submit, as my code examples, the documentation for Objectify:

http://code.google.com/p/objectify-appengine/wiki/IntroductionToObjectify

There's plenty of code there, all of which demonstrates actions that
you need to do in the real world.

I've read the Objectify docs and there are nothing but trivial Car Person examples - all of which we have shown are cleaner and simpler in Twig.

However, I don't expect to convince you of anything.  You seem to
believe that your API is so magnificent that it doesn't require
Javadocs, and that Objectify's iterable query is some sort of bug
magnet.  This makes me question your sanity.

Ha ha well I would love to see some examples of your claims ... then I might be easier to convince. But we both know that won't happen.

If you want to create a Real World application for comparison, I might
be willing to spend a little time creating an Objectify version.
Otherwise, I suggest that any readers actually go through the docs for
both projects and see which one you like better.

My real world application is not possible with Objectify!! It uses OR queries executed in parallel.

You are still mixing the concepts of data model portability and data access
layer (DAOs) portability.

Even if you have Key<?>s in your entities, it doesn't mean you have to
use them outside your DAO layer.  This is up to the app architect.


Are you suggesting creating DTOs to pass data to the other layers?

But it is pointless for me to argue this point; clearly having managed
object graphs can *help* with portability.  It's a grey continuum.
And if you are deeply concerned about this kind of portability, today,
you should be using JPA or JDO.  Maybe you'll end up having a Key here
and there that you must replace, but you won't end up rewriting your
entire DAO layer.

The only data access API that gives you any hope (tenuous as it is) of
real portability is JDO/JPA.

Are you having a laugh? After all your rants about how portability with
JDO-GAE is impossible... that is really grasping at straws.
I claim that Twig data models are more portable that JDO-GAE, JPA and
Objectify data models. Why? Because they are pure POJOs with no low level
datastore dependencies - simple.

Actually, I'm quite serious.  I rant against the wild claims and
religious zeal that the JDO guys express on this list, a religion that
you seem to have become infected with.

Really, and you have not been a little over-zealous making unfounded claims about Objectify? I appreciate that you are starting to concede at least the obvious advantages of Twig.

I've snipped the next bit because I am tired of talking about portability. Usability, performance and maintainability are the strengths of Twig I would prefer to focus on.

In a system such as GAE which makes so much so hard productivity features are a great relief. No OR queries? Of course I value simplicity - but the whole idea of a framework is to push complexity from the user code into the framework. Objectify leaves too much too the developer for my liking. It
is simple - I grant you that - but that makes app code more complex.

It certainly can.  And if you need to do a lot of OR queries that
can't be easily wrapped in a neat utility method (after all, it's
usually just run two queries and union the results), I'll be the first
person to direct users to Twig.

ORs are very common query types.

On the other hand, a simple re-usable utility method is typically not that hard.

It might be harder than you suppose - especially when sorts are involved. I think that is why you haven't responded to my request for the example query I posted earlier.

It is the job of a framework to save developers from having to re-code these "utility methods"


I don't like the idea of entities that look like User #1234 but don't
have the data of User #1234.  This feels like it has a lot of bug
potential to me.

All referenced objects are activated by default - the developer actually has to explicitly choose to use this feature as an optimisation so there are no
surprises.

Objects frequently get loaded and then passed through several function
calls to code that doesn't know the state of the object and might be
maintained by a different engineer.  As someone that thinks
Query.iterator() is errorprone but stateful entities are safe, you
seem to have an odd sense of danger.

I'm not suggesting this is a bad feature, but it has its risks.
You're using an uninitialized POJO to do what JDO/JPA use a proxy for.
At least proxies have the advantage that they tend to work correctly
most of the time and they provide clear error messages when they
don't.

Gavin once told me that the #1 most common issue people have with
Hibernate is "Why do I get this LazyInitializationException?"  In your
system, every one of those errors is going to be an unintended
reference to an uninitialized entity - possibly undetected, returning
bad data.

Say what you will about Key objects, at least they always work.

I don't deny that the developer could hit an initialized object. But given that they have to explicitly turn on this feature I think you are over-stating the danger. The advantages are huge - POJOs and cleaner code.

Managing object identity is a lot more than just keeping an Id field. It is a guarantee that if you load the same instance twice from the datastore they
will be identical instances.  obj1 == obj2
Objectify has no such guarantee so you could end up loading two referenced instances with the same id, making changes and puting them again only for
one to overwrite the other.

Yep.  Objectify entities are plain, boring POJOs that work just like
every other Java object.  You can load them, clone them, save them,
serialize them in and out, whatever.  There is no magic.

I would hardly call an object with such restrictions a POJO. Having two instances of the same entity in memory at the same time is asking for trouble. Unless you do something like implement hashCode and equals on every instance and put realted entities in a HashSet you risk clobbering data.


The Objectify framework has the advantage of simplicity because it has fewer features. The Objectify user code is more complex because the user must do
more "manually".  The merged OR query is just one example of this.
In my opinion the goal for any GAE framework should be to help overcome the great and unusual limitations of the environment. To encapsulate solutions
in one place to avoid repeating them again and again.

We evaluate real-world pain points based on our own and our user's
experiences, then add features to solve those pain points as elegantly
as possible.  OR queries haven't been a pain point.  Maybe they will
be in the future, in which case we'll consider adding the feature.  We
are content to wait for the request.

Are you seriously claiming that OR queries are not common in applications?

Without dirty detection, aren't you likely to persist quite a large
object graph every time you do a put?

No. Updating or storing an item makes all reachable items persistent _only_ if it is not already persistent. Each item that changes must have update
called.

So saves cascade if the entities are new, but not if the entities were loaded?

By the way, how do you distinguish between these three types of relationships:

class One {
   @Id Long id;
}
class Many {
   @Id Long id;
   @Parent Key<One> one;
}

vs:

class One {
   @Id Long id;
}
class Many {
   @Id Long id;
   Key<One> one;
}

vs:

class One {
   @Id Long id;
   List<Many> many;
}
class Many {
   @Id Long id;
}

Replace your Keys with direct references. Remove the @Ids unless they are needed by your application

Twig is already much more capable than JPA on GAE for a very good reason: It is designed specifically to work with GAE. Integrating performance features like "Parallel Asynchronous Commands" into JPA or JDO would be
impossible.

JPA/JDO is getting support for joins.  Are you planning to add this?

I'll grant you that async queries are nice.  I like it enough that
it's a potential future feature for Objectify.

It won't be the first feature copied from Twig: "We like this feature and are assimilating it now :)"

http://groups.google.com/group/google-appengine-java/browse_thread/thread/f20d922ffecb310c

Perhaps in 2012 you'll be adding direct references and ORs. Feel the power of the dark side Jeff.


I can honestly say that without Twig my app would be at least 100 times slower. Why? Embedded collections have probably reduced the multiple queries required in JDO by 10 fold. Parallel queries have now reduced the
query another 10 fold.

I wouldn't be so certain that it's impossible to add embedded
collections to the DN plugin as an extension.  Not that I expect it to
happen anytime soon.

(for those keeping score, Objectify supports embedded collections)

Reducing key strokes is a much lower priority in Twig than creating
readable, maintainable code.
It seems that method naming in Objectify takes the oposite approach.

You should really give it up.  Or talk to a third party about which
Query interface is easier to use and understand.

Your loyalty is impressive but completely unfounded.

Hey, I just noticed something.  Does Twig lack simple batch get()
operations?

I frequently write code like this:

Set<Long> ids = ... // fetch user's friend ids
Collection<Person> friends = ofy.get(Person.class, ids).values();

What is the Twig equivalent?

This would be handled with a simple direct collection reference in Twig like
this:
user.friends

Why do you assume that the friends came from some sort of internal
datastore object?  In my case, the friend ids come from Facebook.  If
you work with data from third parties, you will frequently load
objects with ids that are not of your own making and that have
relationships that are not defined in your data structures.

Batch gets are essential.

OR's are essential - batch gets are a trivial feature that will be added with the load command.

So the batch get by key is really not so useful in Twig - or at least I
haven't had the need for it yet.
 But I can see cases where would be useful
and am planning on adding a fluent load (and delete) commands which - just
like the find and store commands - has "advanced" features such as
returnResultsLater() and bulk load.
I just noticed, how do you set the chunk size in Objectify? I can't see the
option anywhere.

In Twig it is getResultsBy(50)

It's a minor implementation detail that nobody has asked for or cared
about yet.  But if they did, it would probably be Query.chunkSize().

Jolly good.  Give my love to Cassandra

John





--
You received this message because you are subscribed to the Google Groups "Google 
App Engine for Java" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/google-appengine-java?hl=en.

Reply via email to