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.