Hi Christopher,
> Hi Lukas,
>
> I have a(nother?) silly question.
Not so silly!
Thanks for bringing up these things. It was about time someone
challenged my API decisions - luckily before I have released jOOQ 3.0
GA :-)
OK, so there are three topics in this discussion. We can split the
thread in the near future, if things start getting unrelated.
Topic #1: Static vs. contextual Factory methods
===============================================
> Quoting you:
> "While Factory is all static, Executor initialises objects with a
> Configuration. In fact, Executor and Factory share a lot of API, even if
> informally by convention. This leads to things like
> executor.fetch(Factory.select()) being the same as
> executor.select().fetch()".
>
> Why confuse users with this artificial distinction (static vs contextual)
> between Factory and Executor? Why not put all the static methods of Factory
> in the Executor class and get rid of Factory (and static import Executor)?
OK, let's establish terms for this discussion. I like your wording:
1. static - QueryParts are created through static methods from the Factory
2. contextual - QueryParts are created with a Configuration
"attached", through the Executor
Things used to be the way you proposed in jOOQ 2.x. I.e. static and
contextual methods were mixed in a single Factory. The problem this
cause was an essential problem for a fluent API. Because in Java,
static and instance methods occupy the same namespace, Query factory
methods were restricted to being contextual. This is a bit annoying
for two secondary use-cases:
1. Subqueries. Subqueries do not need to be created contextually.
Things would get more readable, if you can just write "select()"
instead of "create.select()"
2. Batch execution. When putting several queries in a batch-style
method, you again had to create queries contextually, even if the
context was not needed.
So, there is a relevant use-case for duplicating the API for query
construction into a static and a contextual part. I think we can agree
on that (?), so let's discuss whether the current solution is good
enough (see topic #2)
Topic #2: "Executor" as a name
==============================
> Also, I don't think Executor is a good name. It is the starting point of
> creating a query and that should be obvious from the name. Moreover, the
> query that Executor allows to build will eventually be transformed to a
> String (getSQL()): it is not necessarily executed, it is more like a
> factory. I think the name "Factory" is way better than "Executor" (no matter
> whether you consider the context-aware methods or static ones, that I just
> suggested to merge in one single class).
Yes, I don't really like the term "Executor" either. It was an obvious
choice in the first refactoring steps of jOOQ 3.0. Meanwhile, the
greater picture is more clear, and it becomes evident that the type
shouldn't be called Executor. On a side-note, it is a bit ironic that
you bring this up just shortly after I've posted this article here
about regular APIs :-)
http://blog.jooq.org/2013/03/30/how-to-design-a-good-regular-api
I think what is really confusing is the fact that users have to make a
conscious decision whether to use the Executor or the Factory as the
entry point for the jOOQ DSL and/or for QueryPart construction. In
other words, the purely technical reason for this distinction (cannot
overload static / non-static) doesn't pull the weight of the added
Executor type.
It would be much better if the single entry point to the jOOQ API was
the Factory, but not in the way you suggest (as this is not possible
in Java). An alternative solution to this problem would be to add a
static "with" keyword to the Factory, with which an "Executor" could
be created (let's keep calling it Executor and rename it later). So
this would be how you'd create "static" subqueries:
select().from(TABLE)
.where(conditions)
.orderBy(ID);
Here's how you'd create "contextual", and thus executable queries:
with(configuration)
.select()
.from(TABLE)
.orderBy(ID)
.fetch();
Here's how you'd use batch queries:
with(connection, dialect) // Alternatively to with(configuration)
.batch(
insertInto(TABLE_A).values(1, 2, 3),
insertInto(TABLE_B).values(4, 5, 6)
)
.execute();
So instead of establishing an Executor instance and letting users know
of it, there would be several overloaded "with()" methods that would
return an Executor instance. They would reflect today's Executor
constructors. (The need for overloading Executor(Configuration) with
Executor(Connection, SQLDialect) and other constructors is being
discussed in another thread).
This would allow for keeping the required distinction between static
and contextual QueryPart construction, but it would seem like the API
was more unified, and users only need to remember Factory as an entry
point.
Now the object returned by "with()" doesn't need to be called
Executor. Neither do we need to use the term "with()", as that might
cause confusion in the future, once jOOQ supports common table
expressions. But you get the idea. What would you think of this
alternative route?
Topic #3: Factory and Executor as short names in general
========================================================
> I also personaly don't like names like "Factory", "Executor", etc. While I
> reckon they are short, they are too broad/generic and in a complex
> application do not immediately make the link to jOOQ. They also don't help
> auto imports, code navigation, Google searches (there are many generic
> classes with the same name), etc. In my view, a name like JOOQFactory would
> be unambiguous: we would know what it creates just from the name and there
> would be no name collisions.
Factory is qualified with org.jooq.impl. Packages do a good job of
disambiguating things, in my opinion. If you're using jOOQ, you will
be using it in a narrow context, i.e. within a DAO. The likelyhood of
ambiguities is slim. Even then, you'll probably static-import
org.jooq.impl.Factory.*;
Also, I don't see a point to prefixing the Factory but not all the
other 100 API types. According to your argument, these types might
need renaming too:
- Field (as in java.lang.reflect.Field)
- Record (dozens of ambiguous occurrences)
- Table (Swing, probably?)
- Schema (XSD, etc)
- You name it
We could discuss a rename from Factory to JOOQ or something like that,
of course. But I will need very compelling reasons to re-write the
whole manual and explain to everyone that the Factory has been
beautified :-)
Cheers
Lukas
PS: Thanks again for bringing these things up!