IWETHEY v. 0.3.0 | TODO
1,095 registered users | 0 active users | 0 LpH | Statistics
Login | Create New User
IWETHEY Banner

Welcome to IWETHEY!

New General description
Junct is a Wiki-like web application; each Topic has its own page. There are also User and Group objects (classes). junct/__init__.py has all of the object definitions; pages.py has most of the HTML formation and handling. One could, if so inclined, ditch the web interface and write (say) a Windows GUI front end without changing anything in __init__.py. Sorry this isn't documented well, I wrote it in a week or so and haven't gotten back to it.

It's built on top of Dejavu, a caching object server framework. Dejavu has the classic 3 layers: UI, Object, and Storage. There are some basic HTML UI components in dejavu/html/, but again you could write a different interface without changing anything in the other two layers. As a matter of fact, I regularly test all Dejavu apps under both Apache2 and IIS by simply turning one Windows service off and the other one on. It's that simple.

Same goes for the storage layer; I provide an ADO storage manager for Access and SQL Server, but it would be little work to write one for Postgres, Oracle, MySQL. The *deployer* then has the option to specify which DB they prefer, rather than the developer.

I'm working on another app called EnDue (Directory, Ledger, Invoice, Inventory, plus custom biz objects)--trying to roll it out here at work this month. That app uses an Access DB for half the data, and a third-party app (The Raiser's Edge from Blackbaud) for the other half. The RE storage is doubly-difficult, because reads are done via ADO calls to an MSDE or SQL Server DB, but writes are done via an API they provide, which doesn't always mirror the object structure of the DB. However, none of that ugly mess is allowed to affect any part of the application layer--it's all done in the storage layer. If when, in the future, we stop using RE and go with another provider, I just write a new storage manager for it, pump all the data out of the old store and into the new one, and proceed on my merry way without rewriting any application code.
New SQL wrapper?
Same goes for the storage layer; I provide an ADO storage manager for Access and SQL Server, but it would be little work to write one for Postgres, Oracle, MySQL. The *deployer* then has the option to specify which DB they prefer, rather than the developer.


Unless one uses lowest-common-denominator SQL and lots of looping, how do you keep it generic across SQL dialects? A generic SQL wrapper API does not exist that I know of. Past attempts to create one have failed.

Anyhow, is there something specific that you think OO does clearly more wonderful than a procedural version of such a thing? Or, does one have to take it as a whole?

(BTW, I added a message above explaining some causes of OR-tool bloat)
________________
oop.ismad.com
Expand Edited by tablizer May 20, 2004, 02:27:17 PM EDT
New Generic SQL wrapper API
[link|http://www.hibernate.org|http://www.hibernate.org]

Supports: Oracle, DB2, Sybase, MS SQL Server, PostgreSQL, MySQL, HypersonicSQL, Mckoi SQL, SAP DB, Interbase, Pointbase, Progress, FrontBase, Ingres, Informix, Firebird

Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New I see bloated people
This is better? Instead of:
\nselect * from bidView\nwhere description like "hibernate%"\n  and amount > 100\n

One writes
  \nList auctionItems = \n  session.createCriteria(AuctionItem.class)\n     .setFetchMode("bids", FetchMode.EAGER)\n     .add(Expression.like("description", desc))\n     .createCriteria("successfulBid")\n       .add(Expression.gt("amount", minAmount))\n     .list();\n

And I am skeptical it can handle the more complex stuff between vendors.
It reminds me of the "bloat joke" on my main anti-OOP page:
\nNORMAL\n\n  print(a + b)\n\nBLOATED\n\n  am = new math.ArithmeticManager()\n  opA = new math.Operand((float) a)\n  opB = new math.Operand((float) b)\n  am.addOperand(opA)\n  am.addOperand(opB)\n  am.operator = new math.operators.Addition()\n  am.executeMathOperation()\n  system.io.output.print(am.mathOperationResult())\n

________________
oop.ismad.com
New Er...
List l = template.find("from User user where user.nickname = ?", nickname); *

Or maybe:
user = template.get(User.class, id);

Hmmm. let's see, after I make some changes to the user, what do I do to save it:
template.saveOrUpdate(user);

And if it's a new user, it will automatically create it for me.

Or let's say I'd like to get all of the accounts associated with that user:
List accounts = user.getAccounts();

What did you do, sort through that site until you found the most convoluted example you could?

One nifty feature of Spring, btw, is that I can use a User object tied to the database as the backing object for a form. Auto-filled HTML forms, auto-parsed form parameters.

Here's some code for a Create New User form:

\n\tpublic ModelAndView onSubmit(HttpServletRequest request, \n\t\t\t\tHttpServletResponse response,\n\t\t\t\tObject command, BindException errors)\n\t\t{\n\t\t\tUser user = (User) command;\n\n\t\t\tint id = mUserManager.createNewUser(user);\n\n\t\t\t// This bit logs the user in as well\n\t\t\tHttpSession sess = request.getSession();\n\t\t\tsess.setAttribute(USER_ID_ATTRIBUTE, new Integer(id));\n\n\t\t\treturn new ModelAndView(new RedirectView(getSuccessView()));\n\t\t}\n\n    protected Object formBackingObject(HttpServletRequest request)\n\t\tthrows ServletException\n\t\t{\n\t\t\tUser user = new User();\n\t\t\tuser.setNickname(request.getParameter("nickname"));\n\t\t\tuser.setUnencryptedPassword(request.getParameter("password"));\n\n\t\t\treturn user;\n\t\t}\n

That plus a little configuration XML that ties that code with the form URI is all I need.

* Note that I am using Hibernate in conjunction with Spring, but that there's not much difference in the basic code either way. This is actual code that I'm using now, incidentally.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New re: Er...
List l = template.find("from User user where user.nickname = ?", nickname);


That is basically just embedding some or all of the query strings into query API's. One can make functions that do similar things if need be.

user = template.get(User.class, id);


One can make a "record = getUser(id)" function if need be. Generally I will only factor SQL to a function if I see it repeated about 3 times. But, most SQL is specific to a task, so little is gained by wrapping it.

What did you do, sort through that site until you found the most convoluted example you could?


Queries can get far more involved than that. That was nothing.

One nifty feature of Spring, btw, is that I can use a User object tied to the database as the backing object for a form.


That is just yet another CRUD-screen (create,read,update,delete) framework it appears.
________________
oop.ismad.com
New Nice attempt
The POINT that you missed is that THERE IS NO BLOAT. You found an example of the programmatic query language that they suggest people NOT use, in order to show how bloated it was. You failed. Accept it and move on. Difficult queries are no more convoluted using Hibernate than they are using SQL. A good many queries are more straight-forward, such as the getAccounts() example. Are you willing to admit this yet?

That is just yet another CRUD-screen (create,read,update,delete) framework it appears.
No, it's quite a bit more flexible than just CRUD. But it makes CRUD dead stupid simple to do.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New re: Nice attempt
We would probably have to do a code-for-code shootout to settle this. A lot of the "simple" examples require a fair amount of set-up work to define stuff (a lot of it essentially duplicating the RDB schemas with an OO twist.)

Even if by chance the code-size was the same (not convinced yet), you still have not justified the extra OR-mapper layer, per other message.
________________
oop.ismad.com
New re: Nice attempt
Hibernate definitions. Note that this can be used to generate the database schema in any of the supported databases automatically.
\n<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE hibernate-mapping PUBLIC\n        "-//Hibernate/Hibernate Mapping DTD//EN"\n        "[link|http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd|http://hibernate.sou...e-mapping-2.0.dtd]">\n\n<!-- $Id: iwethey.hbm.xml 17 2004-04-28 22:13:29Z anderson $ -->\n<hibernate-mapping auto-import="true">\n\n\t<class name="org.iwethey.domain.User" table="iwethey_user" lazy="true">\n\t\t<cache usage="read-write"/>\n\n\t\t<id name="id" column="user_id" unsaved-value="0">\n\t\t\t<generator class="sequence">\n\t\t\t\t<param name="sequence">seq_user</param>\n\t\t\t</generator>\n\t\t</id>\n\t\n\t\t<property name="nickname"/>\n\t\t<property name="encryptedPassword" column="password"/>\n\t\t<property name="created" type="timestamp" insert="false"/> <!-- update="false"/> -->\n\t\t<property name="lastPresent" column="last_present" type="timestamp" insert="false"/>\n\n\t\t<map name="properties" table="user_property" cascade="all" lazy="true">\n\t\t\t<cache usage="read-write"/>\n\t\t\t<key column="user_id"/>\n\t\t\t<index column="name" type="string"/>\n\t\t\t<element column="value" type="string"/>\n\t\t</map>\n\t</class>\n</hibernate-mapping>\n


Data interface class. Exists for the purpose of allowing swappable data sources (note the "implements UserManager"). Not strictly necessary as a separate object/interface if you are using only a single data source.
\npublic class HibUserManager extends HibernateSupportExtensions implements UserManager\n{\n\tpublic List getUserList()\n\t{\n\t\treturn getHibernateTemplate().loadAll(User.class);\n\t}\n\n\tpublic User getUserByNickname(String nickname)\n\t{\n\t\tList l = getHibernateTemplate().find("from User user where user.nickname = ?", nickname);\n\t\tif (l.size() == 1)\n\t\t\treturn (User) l.get(0);\n\t\treturn null;\n\t}\n\n\tpublic User getUserById(int id)\n\t{\n\t\ttry\n\t\t\t{\n\t\t\t\treturn (User) getHibernateTemplate().get(User.class, new Integer(id));\n\t\t\t}\n\t\tcatch (HibernateObjectRetrievalFailureException e)\n\t\t\t{\n\t\t\t\treturn null;\n\t\t\t}\n\t}\n\n\tpublic boolean checkLogin(User user)\n\t{\n\t\tList l = getHibernateTemplate().find(\n\t\t\t"from User user where user.nickname = ? and user.encryptedPassword = ?",\n\t\t\tnew Object[] { user.getNickname(), user.getEncryptedPassword() }\n\t\t\t);\n\t\treturn l.size() == 1;\n\t}\n\n\tpublic void saveUser(User user)\n\t{\n\t\tgetHibernateTemplate().saveOrUpdate(user);\n\t}\n\n\tpublic void saveUserAttributes(User user)\n\t\t{\n\t\t\tif (!user.isAnonymous())\n\t\t\t\tgetHibernateTemplate().saveOrUpdate(user);\n\t\t}\n\n\tpublic void removeUser(User user)\n\t\t{\n\t\t\tif (!user.isAnonymous())\n\t\t\t\tgetHibernateTemplate().delete(user);\n\t\t}\n\n\tpublic int getUserCount()\n\t\t{\n\t\t\treturn single("select count(*) from User user").intValue();\n\t\t}\n\n\tpublic int getActiveUserCount()\n\t\t{\n\t\t\treturn single("select count(*) from User user where (CURRENT_TIMESTAMP - last_present) < interval '10 minutes'").intValue();\n\t\t}\n\n\tpublic boolean getExists(String nickname)\n\t\t{\n\t\t\treturn single("select count(*) from User user where nickname = ?", nickname).intValue() > 0;\n\t\t}\n\n\tpublic boolean getExists(User user)\n\t\t{\n\t\t\treturn getExists(user.getNickname());\n\t\t}\n}\n


User object. Serves as a form backing object as well as a data object. Supports an arbitrary number of properties, any type that can be represented as a string. I've omitted some convenience methods (getPropertyAsBoolean, etc.) that aren't necessary for the purpose of proving the point. This class can also be used in anonymous mode before the user has logged in, allowing preference settings that persist for the session only. Note that other OO languages do not require nearly as much boiler-plate set/get cruft as Java.
\npublic class User implements Serializable\n{\n\tprivate int mId = 0;\n\tprivate String mNickname = null;\n\tprivate String mUnencryptedPassword = null;\n\tprivate String mEncryptedPassword = null;\n\tprivate String mPasswordCheck = null;\n\tprivate Date mCreated = null;\n\tprivate Date mLastPresent = null;\n\tprivate Map mProperties = null;\n\n\tpublic User() { }\n\n\tpublic User(User user)\n\t\t{\n\t\t\tsetFromUser(user);\n\t\t}\n\n\tpublic User(String nickname)\n\t\t{\n\t\t\tsetNickname(nickname);\n\t\t}\n\n\tpublic User(String nickname, String password)\n\t\t{\n\t\t\tthis(nickname);\n\t\t\tsetUnencryptedPassword(password);\n\t\t}\n\n\tpublic void setId(int id) { mId = id; }\n\tpublic int getId() { return mId; }\n\n\tpublic void setNickname(String nickname) { mNickname = nickname; }\n\tpublic String getNickname() { return mNickname; }\n\n\tpublic void setUnencryptedPassword(String password)\n\t\t{\n\t\t\tmUnencryptedPassword = password;\n\t\t\tif (password != null && !password.equals(""))\n\t\t\t\tmEncryptedPassword = encrypt(password);\n\t\t}\n\tpublic String getUnencryptedPassword() { return mUnencryptedPassword; }\n\n\tpublic void setEncryptedPassword(String password) { mEncryptedPassword = password; }\n\tpublic String getEncryptedPassword() { return mEncryptedPassword; }\n\n\tpublic void setPasswordCheck(String passwordCheck) { mPasswordCheck = passwordCheck; }\n\tpublic String getPasswordCheck() { return mPasswordCheck; }\n\n\tpublic void setCreated(Date created) { mCreated = created; }\n\tpublic Date getCreated() { return mCreated; }\n\n\tpublic void setLastPresent(Date lastPresent) { mLastPresent = lastPresent; }\n\tpublic Date getLastPresent() { return mLastPresent; }\n\n\tpublic void setProperty(String name, String value)\n\t\t{\n\t\t\tgetProperties().put(name, value);\n\t\t}\n\n\tpublic Map getProperties()\n\t\t{\n\t\t\tif (mProperties == null)\n\t\t\t\tmProperties = new HashMap();\n\n\t\t\treturn mProperties;\n\t\t}\n\n\tpublic void setProperties(Map props)\n\t\t{\n\t\t\tmProperties = props;\n\t\t}\n\n\tpublic String getProperty(String name, String defaultValue)\n\t\t{\n\t\t\tString val = (String) getProperties().get(name);\n\n\t\t\tif (val == null)\n\t\t\t\treturn defaultValue;\n\n\t\t\treturn val;\n\t\t}\n\n\tpublic void setFromUser(User user)\n\t\t{\n\t\t\tassert user != null;\n\n\t\t\tsetId(user.getId());\n\t\t\tsetNickname(user.getNickname());\n\t\t\tsetUnencryptedPassword(user.getUnencryptedPassword());\n\t\t\tsetEncryptedPassword(user.getEncryptedPassword());\n\t\t\tsetPasswordCheck(user.getPasswordCheck());\n\t\t\tsetCreated(user.getCreated());\n\t\t\tsetLastPresent(user.getLastPresent());\n\t\t\tsetProperties(user.getProperties());\n\t\t}\n\n\tpublic Object clone()\n\t\t{\n\t\t\treturn new User(this);\n\t\t}\n\n\tprivate static final char mHexChars[] =\n\t{\n\t\t'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'\n\t};\n\n\tpublic String encrypt(String buffer)\n\t\t{\n\t\t\tMessageDigest crypt = null;\n\n\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tcrypt = MessageDigest.getInstance("MD5");\n\t\t\t\t}\n\t\t\tcatch (NoSuchAlgorithmException e1)\n\t\t\t\t{\n\t\t\t\t\tLogFactory.getLog(getClass()).error("No MD5 implementation!");\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\tcrypt.update(buffer.getBytes());\n\n\t\t\tbyte[] bytes = crypt.digest();\n\n\t\t\tStringBuffer hex = new StringBuffer(2 * bytes.length);\n \n\t\t\tfor (int i = 0; i < bytes.length; i++)\n\t\t\t\t{\n\t\t\t\t\tbyte bch = bytes[i];\n\n\t\t\t\t\thex.append(mHexChars[(bch & 0xF0) >> 4]);\n\t\t\t\t\thex.append(mHexChars[bch & 0x0F]);\n\t\t\t\t}\n\t\t\n\t\t\treturn hex.toString();\n\t\t}\n\n\tpublic boolean isAnonymous()\n\t\t{\n\t\t\treturn mId == 0;\n\t\t}\n}\n



Omitted: Spring bean factory XML, as this is application dependent and not actually necessary to use the code. It adds things like declarative transaction boundaries, cache controls, and the like.

This is working code. If you don't believe me, go [link|http://lord.gregfolkert.net:8180/iwethey/main.iwt|here]. Note that there are few interface bugs in that version, since fixed.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Forgot to add:
The user properties are lazily loaded when called. This is one of the main reasons I went with Hibernate. The excess code I was able to jettison was just an added benefit.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Aieee! Actual code! HOW DARE YOU!!!


Peter
[link|http://www.debian.org|Shill For Hire]
[link|http://www.kuro5hin.org|There is no K5 Cabal]
[link|http://guildenstern.dyndns.org|Blog]
New Making it interesting
How about a nice useful assignment that all in these parts could actually benefit from. Let's say that Admin goes about building a useful app with OOP techniques. Let's say that Bryce gets to write the same app using only procedural constructs.

The application is the zIWETHEY board. Bryce will have the advantage that Admin will have provided a working set of software that will be open sourced. He can use that to construct a working prototype in any procedural language he so desires (assuming, of course, that the language runs under Apache).

Bryce claims that the procedural version will be much cleaner. Let's see some actual proof.

Let the games begin. :-)
New Heh. I think Bryce would rather have someone else write it
...then he can tear it apart and say, "it's not how *I* would have done it. Case dismissed." ;)
New Don't you know?
Message board is not a "business application"
--

Buy high, sell sober.
New Putting words in my mouth
Bryce claims that the procedural version will be much cleaner. Let's see some actual proof.

I didn't claim that. I only claim that it will not be objectively worse.

The real benefit would probably be that a p/r version would be more consistent from developer to developer because OO is too open-ended. Every professed OO guru does a very different design. OO is all over the fricken map because it the Goto of structuring. Relational rules and the "group by task" of procedural will tend to produce a more consistent and predictable result than OO.
________________
oop.ismad.com
New Actually, what you said was:
"You spend all your code translating back and forth between two discordant paradigms."

So, where's the bloat? Are you ready to admit that it isn't there yet?
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Re: Putting words in my mouth
Relational rules and the "group by task" of procedural will tend to produce a more consistent and predictable result than OO.
Having seen several large procedural database programs, I question the validity of this statement. "Tend" is a weasel word. Where's your proof?
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Code Talks. Bryce Walks.
So let's set our goals a bit more realistic. Let's see if you can produce a version of zIWETHEY software that is not "objectively worse".
New I shall consider it
________________
oop.ismad.com
New Thanks.
Looking at this is an opportunity to learn more about the app, and make the discussions a bit more than rhetoric. Even if you don't want to piece together the whole app, perhaps you can at least show how some of the pieces of it could be written from a P/R perspective.
New If you don't...
... then you forfeit all right henceforth to whine, "show me the code".
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New RE: Are you willing to admit this yet?
Let's see. Wasn't it 1997 or so when this discussion began. And haven't we been through 4 boards (IWETHEY, EZBoard IWETHEY and Jay's OO, and zIWETHEY).

And you really think he's going to admit something after all this time? :-)
New Even OO fans are mixed about OR-mappers
I did NOT write this:

[link|http://www.c2.com/cgi/wiki?ObjectRelationalMappingCostsTimeAndMoney|http://www.c2.com/cg...CostsTimeAndMoney]

Go argue with those guys.
________________
oop.ismad.com
Expand Edited by tablizer May 20, 2004, 11:57:54 PM EDT
New Looks pretty specific.
Took me about two hours to get Hibernate going the first time. Took me another two to port all my old JDBC code to the new mapping stuff. It adds about 5-10% to the runtime costs (which are pretty small to begin with). The cost was nil. Stuff that requires a lot of database interaction back and forth is done in a trigger or stored procedure.

Use a hammer for nails, a screwdriver for screws. This is the basic lesson you have yet to learn.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New In Dejavu, one would write:
f = lambda x: x.description.startswith("hibernate") and x.amount > 100\nfor unit in recall(Thing, logic.Expression(f)):\n    do_something_with(unit)


instead of:

sql = 'select * from bidView where description like "hibernate%" and amount > 100'\nfor row in db.execute(sql, connection):\n   do_something_with(row)


...I don't see any bloat. On the contrary, the first one is written in the same programming language throughout. The second one introduces a declarative language (SQL) inside the original application language. And it only applies to databases where Like is a valid operator, and where the percent-sign is a wildcard character, and where double-quotes are valid delimiters, and where keywords (like 'select') can be lowercase, and where bidView isn't forced into a namespace (with a prefix), and where 'amount' and 'description' are not reserved words.

In addition, user input is made far more safe--you can't simply insert "; DELETE * FROM important_table" into Dejavu code. ;)
New Re: In Dejavu, one would write:
> f = lambda x: x.description.startswith("hibernate") and x.amount > 100\n> for unit in recall(Thing, logic.Expression(f)):\n>     do_something_with(unit)
This looks a lot like the criteria library ([link|http://onestepback.org/index.cgi/Tech/Ruby/Criteria.rdoc|http://onestepback.o...uby/Criteria.rdoc]). Is the implementation based on similar principles?
--
-- Jim Weirich jim@weirichhouse.org [link|http://onestepback.org|http://onestepback.org]
---------------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
New An earlier version was like that.
I had a class which would absorb criteria via Python expressions, so:

e = logic.Expression()\ne.attribute == 3


would trigger:

class Expression(object):\n    def __eq__(self, other):\n        stack.append(operator.eq, other)


Etcetera. Then I would pass around the stack and evaluate it as necessary. But I also (like Criteria) had the issue of not being able to override shortcut And and Or (I used binary & and | instead), and it got a bit ugly. In addition, I was abusing normal syntax--as above, line 2, most manipulations took a comparison and didn't return or assign anything; it wasn't very natural.

So, after seeing a brilliant post by Raymond Hettinger on c.l.p., I wrote two things: an EarlyBinder and a LambdaDecompiler class. Passing a lambda (a Python anonymous function) into an Expression constructor now does early binding via a bytecode Visitor, grabbing globals and cell objects from the closure and dereferencing them (making them constants), then making a new function object. At that point, I'm free to pass it around, even make a string out of it and store it in a DB, because all variables are either arguments to the function, or constants. Flexibility of function is provided through a single mechanism; you can write:

lambda x, **kw: x.Size > kw['Size']


..where kw is keyword arguments--a dictionary (mapping; hash to you Perlers).

The LambdaDecompiler also is a bytecode Visitor, and produces the Python source code from bytecode--that's how I get a string to store. But, having that decompiler core, I subclass it and write SQLDecompilers as well. So the above decompiles into SQL Server (ADO) as:

"WHERE [Size] > %(Size)s" % kwargs


...which, when evaluated with kwargs = {'Size': 3}, yields WHERE [Size] > 3. This gets me the speed boost you mentioned (avoiding 'SQL fragments').

But it was also important for me to have an expression which I could then pass a fully-formed class and test it, because:

1) I have an in-memory object cache, and I need to filter it by the same logic, and
2) The match between Python logic and SQL is imperfect. For example, == is case-sensitive in Python but -insensitive in ADO SQL. It's fastest just to create the class object and run it through the lambda than try to wrangle SQL Server into making the search case-sensitive, which is set database-wide, per column, *and* per query IIRC.

The only ugly bit now is that it's CPython-specific, it won't work on Jython (Python which runs on the JVM), because the bytecode is different. Meh. One thing I really like is that the application code (what a developer using my framework would write) doesn't mention SQL at all. So you can use exactly the same code for huge DB tables, or 10-item in-memory lists, and leave those decisions about the best storage mechanism up to the deployers. They can decide that a list of 10 small items should stay in memory, and the huge table shouldn't. Or vice-versa.
New Forgot: code links
The logic module contains the Expression class, which wraps up the lambdas and adds some sugar, like simpler filters, and allowing you to add (logical-and) Expressions together:

>>> f = logic.Expression(lambda x: x.Size > 3)\n>>> g = logic.filter(Color='Blue')\n>>> f += g\n>>> f\nlogic.Expression(lambda x: (x.Size > 3) and (x.Color == 'Blue'))


The codewalk module does the bytecode inspection, etc.

Both at [link|http://www.aminus.org/rbre/python/index.html|http://www.aminus.or...python/index.html]
New ICLRPD
It only applies to databases where Like is a valid operator, and where the percent-sign is a wildcard character, and where double-quotes are valid delimiters, and where keywords (like 'select') can be lowercase, and where bidView isn't forced into a namespace (with a prefix), and where 'amount' and 'description' are not reserved words.
===

Implicitly condoning stupidity since 2001.
New Why learn and/or create another query language?
SQL is fairly well known. Why introduce yet another query language for developers to learn? Why not come up with a generic SQL dialect and then translate it into different dialects instead of a very different query language into SQL dialects?

Personally I see that most places don't swap DB vendors that often so it is not worth worrying about.

I would like to toss SQL also for something easier to standardize, but your approach is not it. BTW

description.startswith("hibernate")

is much more cluttery than

like "hibernate%"

One could make string processing functions to do something similar if need be, I would note. At least get rid of that damned demeter-violating dot bloat and make it just "startsWith()".
________________
oop.ismad.com
New In case you missed it:
as I said, I am not introducing another query language. The language which you are viewing as "another query language" is nothing more nor less than pure Python, and it applies perfectly to the fully-formed Python objects with which I wish to work. For example, with the expression:

f = lambda x: x.description.startswith("hibernate")

I have just defined an anonymous function in Python. I can then use it directly, without any further translation, on a Thing object:

class Thing(object):\n    def __init__(self, description):\n        self.description = description\n\nbear = Thing("hibernates in winter")


And f(bear) returns True without any intermediate magic. I hope you're not saying that calling a function is more than a programmer can handle. I will concede the fact that lambdas seem to mystify some people.

Given that simplicity, since functions are first-class objects in Python, I can pass that function down to a server like so:

hibernators = namespace.recall(Thing, f)

...and get back a list of all Thing objects for which the function f returns True.

Second point you might have missed: not every storage mechanism is going to be SQL-based. Some might be better off without persistence altogether. Some might be better off with a bsddb. So my solution is even more generic than a "generic SQL dialect".

Third, don't cheat. You wrote:
description.startswith("hibernate")

is much more cluttery than

like "hibernate%"


...conveniently leaving out the field name in your example to make it shorter. At the least, you should have written:

description.startswith("hibernate")

is much more cluttery than

description like "hibernate%"


I won't digress again into how UN-generic and cluttery "like" and "%" are. But I will note that new developers are far more likely to grok my Python syntax at first glance than your SQL.
New only for the trivial
conveniently leaving out the field name in your example to make it shorter.


I assure you it was not intentional. I apologize for the error.

But I will note that new developers are far more likely to grok my Python syntax at first glance than your SQL.


More developers know SQL than know Python. And I am still skeptical it can handle non-trivial queries.

BTW, How would your framework handle this:
\n  SELECT AVG(GPA) FROM (\n\tSELECT AVG(grade) AS GPA FROM Grades GROUP BY studentID\n  )\n

It calculates total GPA with an equal weight per student rather than per class.
________________
oop.ismad.com
New There are multiple ways of doing that...
...depends to a large extent on how the designer puts things together. If we had, for example, a Grade Unit and a Student Unit:

class Grade(dejavu.Unit):\n    pass\nGrade.set_properties({'Value': float,\n                      'StudentID': unicode})\n\nclass Student(dejavu.Unit):\n    def GPA(self):\n        grades = [x.Value for x in self.Grade()]\n        if grades:\n            return sum(grades) / len(grades)\n        else:\n            return 0.0  # This may not be what you want\n\nnamespace.associate(Student, 'ID', Grade, 'StudentID')


That .associate function binds a new .Grade() method to the Student class*; said method looks up all Grade objects which have a StudentID equal to our Student.ID; storage managers are free to optimize that call with a JOIN if they manage both classes**. Our Student.GPA() function uses this (as "self.Grade()") to recall associated units.

So developer code to calc the GPA for multiple students would then look like this (assuming you want all students, all years, etc.):

gpas = [x.GPA() for x in namespace.recall(Student)]\nif gpas:\n    avg_gpa = sum(gpas) / len(gpas)\nelse:\n    avg_gpas = 0.0 # Again, this may not satisfy requirements...


Is it as fast as straight SQL? Guaranteed not. But is it fast enough? Probably. If it isn't, there's nothing stopping the developer from hand-crafting an SQL statement and bypassing some of the layers, if he wants to completely sacrifice maintainability and portability. But I've built three apps on top of this framework now, and haven't run into a speed conflict yet.


Fu xiansheng


* And, incidentally, makes a reciprocal Student() method for the Grade class.

** However, one of the design points of Dejavu is that the framework does not assume all data is managed by the same storage manager unless explicitly told so by the deployer. At my company, for example, I have expense Transactions in one store and income in another, and have to mix them to show, say, amount paid on an invoice. This is done transparently from the point of view of application code--it's handled by a mixing Unit Server in the middle layer. When the day comes that we decide to stop using the second store (which is 3rd party code), all I have to do is change a line in a .conf file, and roll on. I could even build a tool very quickly to migrate the data for me; it's on my list of things to write for version 4.1.
New LCD *for my framework*
First, I'm not sure what you mean by "lots of looping".

Second, if you look at one of my storage managers, you'll see the interface consists of the methods:

1. loader(), which iterates over Units, which are the building-block of Dejavu apps. This is similar to an SQL SELECT.
2. save() = SQL UPDATE
3. destroy() = SQL DELETE
4. max_id() or, alternately, reserve() = SQL Max(ID)
5. create(), which for a DB creates the table. = SQL CREATE TABLE

The only thing most direct-to-DB users want outside of those 5 is JOINs, which haven't been a performance issue for me.

Anyhow, is there something specific that you think OO does clearly more wonderful than a procedural version of such a thing? Or, does one have to take it as a whole?


As I've said, my design allows me to hot-swap UI's and data stores (which don't even have to be databases), pushing those decisions out of the hands of the developer and into those of the deployer where they belong. I can make a single version with multiple, selectable *architectural* components (selectable at runtime, not compile time). A procedural equivalent would have to either:

1. Build all such UIs and data connectors into the monolithic app, with if..then's scattered throughout the code to select among them. The more choices, the more spaghetti.

or

2. Package those as components which are selected at compile time. Then you end up with a MySQL/web version, and a MySQL/GNOME version, and a MySQL/Win2k version, and a Postgres/web version, and a Postgres/GNOME version... etc.

both of which lead to:

3. Limit the interfaces and datastore options to one or two choices.

For the Junct application, the same goes for plugins, converters, HTML rules, importers, and skins.
New RDBMS > "data store"
Databases provide more than just "storage". Example:

* Persistence
* Query languages or query ability
* metadata repository
* State management
* Multi-user contention management and concurrency (locks, transactions, rollbacks, etc.)
* Backup and replication of data
* Access security
* Data computation/processing (such as aggregation and cross-referencing)
* Data rule enforcement or validation
* Multi-language and multi-application data sharing

If you use them ONLY for storage, you are wasting them and probably reinventing many of these things from scratch or getting them from the OR tool. Thus, the OR tool becomes a half-ass database of it's own.

The only thing most direct-to-DB users want outside of those 5 is JOINs, which haven't been a performance issue for me.


So you reinvent joins from scratch? Joins are a very nice feature that I would hate to code manually.

As I've said, my design allows me to hot-swap UI's and data stores


The interfaces and approaches for UI's are usually so different that one cannot just swap them in and out like changing lightbulbs. See [link|http://www.c2.com/cgi/wiki?SeparateDomainFromPresentation|http://www.c2.com/cg...nFromPresentation]

You are essentially putting a protocol on top of a protocol.

Regarding the database, most places don't switch the database often enough to justify heavy rapping. It is anti-YAGNI to add it without knowing you will likely need it.

Can you plug-swap your OR mapper? Same issue. Why is getting locked into a DB vendor more evil than getting locked into a specific OR mapper?

Build all such UIs and data connectors into the monolithic app, with if..then's scattered throughout the code to select among them. The more choices, the more spaghetti.


I don't know why you keep using that word "monolithic". Applications are broken up into relatively independent "tasks" that feed off the DB. As far as "scattering" stuff, OO does not solve it, only changes what is scattered. It is like mapping 2+ dimensional something into a one-dimensional surface, you can only "group by" one primary factor at a time. It is a zero-sum grouping game.

Actually, one of the purposes of using a database is that you can produce a view that gives whatever perspective or grouping you want. Thus, the more you data-tize app information, the less you are coupled to the viewpoint of the original coder or information creator. You can create your own custom view of the information. Tables liberate!
________________
oop.ismad.com
New Re: RDBMS > "data store"
Oddly enough, the OR libraries I've used have made good use of the underlying RDBMS's features, while adding some on top. You're projecting again.

The interfaces and approaches for UI's are usually so different that one cannot just swap them in and out like changing lightbulbs.
Talking out of your ass again, I see. I have code at work at this moment that presents 7 different views (large view, dynamic large view, mini view, dynamic mini view, server-generated chart view, dynamic applet chart view, and CSV view) of the same data. So that's 7 different (in some cases, dramatically different) UIs, all running from exactly the same data source. Plus, I can swap in a test data source for the real one in order to run unit tests. The unit tests don't even need a database connection to run, in fact.

You *can* swap them in and out. It's easy. I do it all the time.

You can create your own custom view of the information.
Views are great for OR mappers, by the way. ;-)

Poor Bryce, has a hammer and all he wants are nails.

[Edit: I can't count, apparently.]
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
Expand Edited by admin May 20, 2004, 11:30:37 PM EDT
New still have not justified yet another tool/layers
I have code at work at this moment that presents 4 different views (large view, dynamic large view, mini view, dynamic mini view, server-generated chart view, dynamic applet chart view, and CSV view) of the same data.


I meant like taking a web app and switching to a VB/Delphi-like GUI and visa versa, not a drill-down report set.

You still have not justified the OR-mapper yet. All else being equal, don't add extra layers/tools if you don't need them.
________________
oop.ismad.com
New Re: still have not justified yet another tool/layers
I can use the same data layer with a Swing app if I wish. No changes. Same data model, same data objects, same data methods.

I found that Hibernate cut my data access code by about half or more. Is that enough justification for you?
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New before and after
I can use the same data layer with a Swing app if I wish. No changes. Same data model, same data objects, same data methods.


So, they have a specific inter-product connection. Because of standards like ODBC, almost any language can use RDBMS data, I would note.

I found that Hibernate cut my data access code by about half or more. Is that enough justification for you?


No, because I would have to see your "before" code.
________________
oop.ismad.com
New Re: before and after
So, they have a specific inter-product connection. Because of standards like ODBC, almost any language can use RDBMS data, I would note.
Other languages can go against the same tables/views I do. Big deal.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Then why have an OR-mapper middleman?
________________
oop.ismad.com
Expand Edited by tablizer May 22, 2004, 01:37:16 AM EDT
New Because:
Reasons to use it over straight JDBC:

"Hibernate generates SQL for you, relieves you from manual result set handling and object conversion and keeps your application portable to all SQL databases. Hibernate provides transparent persistence, the only requirement for a persistent class is a no-argument constructor."

Reasons to use it over straight SQL:

Dual layer caching
Lazy instantiation
Natural object-oriented manipulation of data
Database/data source independence
Query caching
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New I forgot about query caching--a big part of my other app.
New Those are problems that OO introduces
Hibernate generates SQL for you

SQL is pretty compact. It is hard to beat in code size. And one can make little functions for patterns that are used often.

relieves you from manual result set handling

What exactly is "manual result set handling"?

and object conversion and keeps your application portable to all SQL databases.

I am still skeptical that it can handle more complex SQL conversions. And, one does not need OO to make lowest-common-denominator SQL wrappers/helpers.

Hibernate provides transparent persistence

What is transparent persistence? Sounds like something that only matters to OO heads because you have two databases: your application object RAM web and the database. If you talk directly to the database, you don't have this problem. An SQL UPDATE statement simply says "change this". OO creates a problem because you have two "state things" that must be coordinated. You have one "noun model" in app RAM and another in the database (which may be RAM or disk). They have to do the Tango.

Natural object-oriented manipulation of data

Oxymoron. Perhaps you mean it builds those monotonous set/gets. "Natural" my ass.

Query caching

Query string caching or query results caching?
________________
oop.ismad.com
New Re: Those are problems that OO introduces
SQL is pretty compact. It is hard to beat in code size. And one can make little functions for patterns that are used often.
SQL is compact. The procedural code needed to manipulate the SQL and the results is not so compact.

What exactly is "manual result set handling"?
while (rs.hasNext()) { extract row information }

I am still skeptical that it can handle more complex SQL conversions. And, one does not need OO to make lowest-common-denominator SQL wrappers/helpers.
So show one that it can't handle. One doesn't "need" OO to do anything. I stated that that was a reason to prefer O-R mapping over JDBC.

What is transparent persistence? Sounds like something that only matters to OO heads because you have two databases: your application object RAM web and the database. If you talk directly to the database, you don't have this problem. An SQL UPDATE statement simply says "change this". OO creates a problem because you have two "state things" that must be coordinated. You have one "noun model" in app RAM and another in the database (which may be RAM or disk). They have to do the Tango.
If you talk directly to the database, you lose opportunities for caching the data closer to where it is used. You also lose opportunities for creating screens that collect changes serially, then post them to the database all at once.

Oxymoron. Perhaps you mean it builds those monotonous set/gets. "Natural" my ass.
Natural within an existing OO system, as opposed to combining OO with SQL.

Query string caching or query results caching?
Neither. Compiled query caching, to remove the need to parse "select * from foo" every time it's used.

I note that you omitted:

Dual layer caching
Lazy instantiation
Database/data source independence

Am I to take this to mean that you agree that these are benefits?
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New response
I would like to see some psuedo-code or details for how you avoid "manual result set handling".

So show [SQL query] that it can't handle.


I posted one I would like to see in a nearby message. The "GPA" one.

If you talk directly to the database, you lose opportunities for caching the data closer to where it is used. You also lose opportunities for creating screens that collect changes serially, then post them to the database all at once.


I would like a more specific example.

Compiled query caching, to remove the need to parse "select * from foo" every time it's used.


That is called a "stored procedure". But, if it is DB-neutral, what are you sending to the DB itself? Not SQL?

I note that you omitted: Dual layer caching, Lazy instantiation, Database/data source independence


I suspect the first 2 are something specific to an OO-centric design. The last one was already discussed. I doubt one can nicely put nearly all SQL behind an API. And if possible, I doubt only OO can do it well.
________________
oop.ismad.com
New Re: response 1
I would like to see some psuedo-code or details for how you avoid "manual result set handling".
No pseudo-code, bunky. This here's th' real stuff.

This is the JDBC equivalent of HibUserManager, albeit an older version of the interface. Note that even so, this is much better than "straight" JDBC in that it has been Springified. Raw JDBC has a lot more try/catch logic.

"mapRow()" is an example of manual result set handling. There will be one line per column in the table, at least.
\npublic class JdbcUserManager implements UserManager\n{\n    private DataSource mDatasource;\n\n\tprivate HashMap mUserCache = new HashMap();\n\n\tprivate UserQuery mUserNicknameRetriever = null;\n\n\tprivate UserQuery mUserIdRetriever = null;\n\n\tprivate UserQuery mAllUsersRetriever = null;\n\n\tprivate SqlFunction mUserLogin = null;\n\n\tprivate SqlUpdate mUserCreater = null;\n\n\tprivate SqlUpdate mUserRemover = null;\n\n\tprivate SqlUpdate mUserUpdatePassword = null;\n\n\tprivate SqlFunction mUserCounter = null;\n\n\tprivate SqlFunction mUserExists = null;\n\n\tprivate SqlFunction mActiveUserCounter = null;\n\n\tprivate SqlUpdate mUserPresent = null;\n\n\tprivate UserPropertyQuery mUserPropertyRetriever = null;\n\n\tprivate UserPropertiesQuery mAllUserPropertiesRetriever = null;\n\n\tprivate SqlFunction mUserPropertySetter = null;\n\n    public List getUserList()\n\t\t{\n\t\t\treturn mAllUsersRetriever.execute();\n\t\t}\n\n    public User getUserByNickname(String nickname)\n\t\t{\n\t\t\tUser user = (User) mUserCache.get(nickname);\n\n\t\t\tif (user == null)\n\t\t\t\t{\n\t\t\t\t\tuser = (User) mUserNicknameRetriever.findObject(nickname);\n\t\t\t\t\tif (user != null)\n\t\t\t\t\t\tmUserCache.put(nickname, user);\n\t\t\t\t}\n\n\t\t\treturn user;\n\t\t}\n\n    public User getUserById(int id)\n\t\t{\n\t\t\treturn (User) mUserIdRetriever.findObject(id);\n\t\t}\n\n    public boolean checkLogin(User user)\n\t\t{\n\t\t\tif (mUserLogin.runGeneric(new Object[] { user.getNickname(), user.getEncryptedPassword() }) == null)\n\t\t\t\treturn false;\n\t\t\telse\n\t\t\t\treturn true;\n\t\t}\n\n    public void createNewUser(User user)\n\t\t{\n\t\t\tString password = user.getEncryptedPassword();\n\t\t\tint count = mUserCreater.update(new Object[] { user.getNickname(), password });\n\t\t}\n\n\tpublic void saveUser(User user)\n\t\t{\n\t\t\tif (userExists(user))\n\t\t\t\t{\n\t\t\t\t\tif (user.getEncryptedPassword() != null && user.getEncryptedPassword().length() > 0)\n\t\t\t\t\t\tmUserUpdatePassword.update(user.getEncryptedPassword(), user.getNickname());\n\t\t\t\t}\n\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcreateNewUser(user);\n\t\t\t\t}\n\n\t\t\tMap props = user.getProperties();\n\t\t\tif (props != null)\n\t\t\t\t{\n\t\t\t\t\tSet keys = props.keySet();\n\t\t\t\t\tIterator iter = keys.iterator();\n\t\t\t\t\twhile (iter.hasNext())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tString key = (String) iter.next();\n\t\t\t\t\t\t\tsetUserProperty(user.getId(), key, (String) props.get(key));\n\t\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\tmUserCache.remove(user.getNickname());\n\t\t}\n\n    public void removeUser(User user)\n\t\t{\n\t\t\tlogger.info("deleting user: " + user.getNickname());\n\n\t\t\tint count = mUserRemover.update(user.getNickname());\n\t\t\tmUserCache.remove(user.getNickname());\n\t\t}\n\n    public void userPresent(User user)\n\t\t{\n\t\t\tint count = mUserPresent.update(new Object[] { new Timestamp(user.getLastPresent().getTime()),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t   user.getNickname() } );\n\t\t}\n\n\tpublic int getUserCount()\n\t\t{\n\t\t\treturn mUserCounter.run();\n\t\t}\n\n\tpublic int getActiveUserCount()\n\t\t{\n\t\t\treturn mActiveUserCounter.run(new Object[] {"10 minutes"});\n\n\t\t}\n\n\tpublic boolean userExists(String nickname)\n\t\t{\n\t\t\treturn mUserExists.run(new Object[] {nickname} ) == 1;\n\t\t}\n\n\tpublic boolean userExists(User user)\n\t\t{\n\t\t\treturn userExists(user.getNickname());\n\t\t}\n\n\tpublic Map getUserProperties(User user)\n\t\t{\n\t\t\treturn mAllUserPropertiesRetriever.execute(user.getId());\n\t\t}\n\n\tpublic String getUserProperty(int id , String name)\n\t\t{\n\t\t\treturn (String) mUserPropertyRetriever.findObject(\n\t\t\t\tnew Object[] { new Integer(id), name }\n\t\t\t\t);\n\t\t}\n\n\tpublic void setUserProperty(int id, String name, String value)\n\t\t{\n\t\t\tint count = mUserPropertySetter.run(\n\t\t\t\tnew Object[] { new Integer(id), name, value }\n\t\t\t\t);\n\t\t}\n\n\tpublic void clearUserCache()\n\t\t{\n\t\t\tmUserCache = new HashMap();\n\t\t}\n\n    protected class UserQuery extends MappingSqlQuery\n\t{\n        protected UserQuery(DataSource ds, String sql)\n\t\t\t{\n\t\t\t\tsuper(ds, sql);\n\t\t\t}\n \n        protected Object mapRow(ResultSet rs, int rowNum) throws SQLException\n\t\t\t{\n\t\t\t\tString nickname = rs.getString("nickname");\n\t\t\t\tUser user = (User) mUserCache.get(nickname);\n\t\t\t\t\n\t\t\t\tif (user == null)\n\t\t\t\t\t{\n\t\t\t\t\t\tuser = new JdbcUser(JdbcUserManager.this, rs);\n\n\t\t\t\t\t\tuser.setProperties(JdbcUserManager.this.getUserProperties(user));\n\n\t\t\t\t\t\tmUserCache.put(nickname, user);\n\t\t\t\t\t}\n\n\t\t\t\treturn user;\n\t\t\t}\n\n    }\n\n    protected class UserPropertyQuery extends MappingSqlQuery\n\t{\n        protected UserPropertyQuery(DataSource ds, String sql)\n\t\t\t{\n\t\t\t\tsuper(ds, sql);\n\t\t\t}\n \n        protected Object mapRow(ResultSet rs, int rowNum) throws SQLException\n\t\t\t{\n\t\t\t\treturn rs.getString("value");\n\t\t\t}\n\n    }\n\n\tpublic class UserPropertiesQuery extends SqlOperation\n\t{\n\t\tpublic UserPropertiesQuery(DataSource ds, String sql)\n\t\t\t{\n\t\t\t\tsetDataSource(ds);\n\t\t\t\tsetSql(sql);\n\t\t\t}\n\n\t\tpublic Map execute(int id)\n\t\t\tthrows DataAccessException\n\t\t\t{\n\t\t\t\tPropertyHandler handler = new PropertyHandler();\n\t\t\t\tgetJdbcTemplate().query(newPreparedStatementCreator(new Object[] { new Integer(id) } ), handler);\n\t\t\t\treturn handler.getResults();\n\t\t\t}\n\n\t\tprivate class PropertyHandler implements RowCallbackHandler\n\t\t{\n\t\t\tprivate Map mResults = new HashMap();\n\n\t\t\tpublic void processRow(java.sql.ResultSet rs)\n\t\t\t\tthrows SQLException\n\t\t\t\t{\n\t\t\t\t\tmResults.put(rs.getString("name"), rs.getString("value"));\n\t\t\t\t}\n\n\t\t\tMap getResults() { return mResults; }\n\t\t}\n\t}\n\n\tprivate static final String GET_ALL_USERS_SQL = \n\t"select user_id, nickname, created, last_present from iwethey_user order by nickname";\n\n\tprivate static final String GET_USER_SQL = \n\n\t"select user_id, nickname, created, last_present from iwethey_user where nickname = ?";\n\n\tprivate static final String GET_USER_ID_SQL = \n\t"select user_id, nickname, created, last_present from iwethey_user where user_id = ?";\n\n\tprivate static final String USER_LOGIN_SQL = \n\t"select 1 from iwethey_user where nickname = ? and password = ?";\n\n\tprivate static final String CREATE_USER_SQL = \n\t"insert into iwethey_user ( nickname, password ) values (?, ?)";\n\n\tprivate static final String REMOVE_USER_SQL = \n\t"delete from iwethey_user where nickname = ?";\n\n\tprivate static final String COUNT_USERS_SQL = \n\t"select count(1) from iwethey_user";\n\n\tprivate static final String USER_EXISTS_SQL = \n\t"select count(1) from iwethey_user where nickname = ?";\n\n\tprivate static final String COUNT_ACTIVE_USERS_SQL = \n\t"select count(nickname) as usercount from iwethey_user where ('now' - last_present) < interval ?";\n\n\tprivate static final String USER_PRESENT_SQL = \n\t"update iwethey_user set last_present = ? where nickname = ?";\n\n\tprivate static final String USER_UPDATE_PASSWORD_SQL = \n\t"update iwethey_user set password = ? where nickname = ?";\n\n\tprivate static final String GET_USER_PROPERTY_SQL = \n\t"select value from user_property where user_id = ? and name = ?";\n\n\tprivate static final String GET_ALL_USER_PROPERTIES_SQL = \n\t"select user_id, name, value from user_property where user_id = ?";\n\n\tprivate static final String SET_USER_PROPERTY_SQL = \n\t"select setUserProperty(?, ?, ?)";\n\n    public void setDataSource(DataSource ds)\n\t\t{\n\t\t\tmDatasource = ds;\n\n\t\t\tmAllUsersRetriever = new UserQuery(ds, GET_ALL_USERS_SQL);\n\t\t\tmAllUsersRetriever.compile();\n\n\t\t\tmUserNicknameRetriever = new UserQuery(ds, GET_USER_SQL);\n\t\t\tmUserNicknameRetriever.declareParameter(new SqlParameter(java.sql.Types.VARCHAR));\n\t\t\tmUserNicknameRetriever.compile();\n\n\t\t\tmUserIdRetriever = new UserQuery(ds, GET_USER_ID_SQL);\n\t\t\tmUserIdRetriever.declareParameter(new SqlParameter(java.sql.Types.INTEGER));\n\t\t\tmUserIdRetriever.compile();\n\n\t\t\tmUserLogin = new SqlFunction(ds, USER_LOGIN_SQL);\n\t\t\tmUserLogin.declareParameter(new SqlParameter(java.sql.Types.VARCHAR));\n\t\t\tmUserLogin.declareParameter(new SqlParameter(java.sql.Types.VARCHAR));\n\t\t\tmUserLogin.compile();\n\n\t\t\tmUserCreater = new SqlUpdate(ds, CREATE_USER_SQL);\n\t\t\tmUserCreater.declareParameter(new SqlParameter(java.sql.Types.VARCHAR));\n\t\t\tmUserCreater.declareParameter(new SqlParameter(java.sql.Types.VARCHAR));\n\t\t\tmUserCreater.compile();\n\n\t\t\tmUserRemover = new SqlUpdate(ds, REMOVE_USER_SQL);\n\t\t\tmUserRemover.declareParameter(new SqlParameter(java.sql.Types.VARCHAR));\n\t\t\tmUserRemover.compile();\n\n\t\t\tmUserPresent = new SqlUpdate(ds, USER_PRESENT_SQL);\n\t\t\tmUserPresent.declareParameter(new SqlParameter(java.sql.Types.TIMESTAMP));\n\t\t\tmUserPresent.declareParameter(new SqlParameter(java.sql.Types.VARCHAR));\n\t\t\tmUserPresent.compile();\n\n\t\t\tmUserUpdatePassword = new SqlUpdate(ds, USER_UPDATE_PASSWORD_SQL);\n\t\t\tmUserUpdatePassword.declareParameter(new SqlParameter(java.sql.Types.VARCHAR));\n\t\t\tmUserUpdatePassword.declareParameter(new SqlParameter(java.sql.Types.VARCHAR));\n\t\t\tmUserUpdatePassword.compile();\n\n\t\t\tmUserPropertyRetriever = new UserPropertyQuery(ds, GET_USER_PROPERTY_SQL);\n\t\t\tmUserPropertyRetriever.declareParameter(new SqlParameter(java.sql.Types.INTEGER));\n\t\t\tmUserPropertyRetriever.declareParameter(new SqlParameter(java.sql.Types.VARCHAR));\n\t\t\tmUserPropertyRetriever.compile();\n\n\t\t\tmAllUserPropertiesRetriever = new UserPropertiesQuery(ds, GET_ALL_USER_PROPERTIES_SQL);\n\t\t\tmAllUserPropertiesRetriever.declareParameter(new SqlParameter(java.sql.Types.INTEGER));\n\t\t\tmAllUserPropertiesRetriever.compile();\n\n\t\t\tmUserPropertySetter = new SqlFunction(ds, SET_USER_PROPERTY_SQL);\n\t\t\tmUserPropertySetter.declareParameter(new SqlParameter(java.sql.Types.INTEGER));\n\t\t\tmUserPropertySetter.declareParameter(new SqlParameter(java.sql.Types.VARCHAR));\n\t\t\tmUserPropertySetter.declareParameter(new SqlParameter(java.sql.Types.VARCHAR));\n\t\t\tmUserPropertySetter.compile();\n\n\t\t\tmUserCounter = new SqlFunction(ds, COUNT_USERS_SQL);\n\t\t\tmUserCounter.compile();\n\n\t\t\tmUserExists = new SqlFunction(ds, USER_EXISTS_SQL);\n\t\t\tmUserExists.declareParameter(new SqlParameter(java.sql.Types.VARCHAR));\n\t\t\tmUserExists.compile();\n\n\t\t\tmActiveUserCounter = new SqlFunction(ds, COUNT_ACTIVE_USERS_SQL);\n\t\t\tmActiveUserCounter.declareParameter(new SqlParameter(java.sql.Types.VARCHAR));\n\t\t\tmActiveUserCounter.compile();\n\t\t}\n}\n


In order to have lazy instantiation and caching, you need the JdbcUser object as well:
\npublic class JdbcUser extends User\n{\n\tprivate UserManager mManager = null;\n\n\tpublic JdbcUser() { }\n\n\tpublic JdbcUser(User user)\n\t\t{\n\t\t\tsuper(user);\n\t\t}\n\n\tpublic JdbcUser(UserManager manager)\n\t\t{\n\t\t\tsuper(manager);\n\t\t}\n\n\tpublic JdbcUser(UserManager manager, ResultSet rs)\n\t\tthrows SQLException\n\t\t{\n\t\t\tsuper(manager);\n\n\t\t\tsetId(rs.getInt("user_id"));\n\t\t\tsetNickname(rs.getString("nickname"));\n\t\t\tsetCreated(rs.getTimestamp("created"));\n\t\t\tsetLastPresent(rs.getTimestamp("last_present"));\n\t\t}\n\n\tpublic JdbcUser(UserManager manager, String nickname, String password)\n\t\t{\n\t\t\tsuper(manager, nickname, password);\n\t\t}\n\n\tpublic Map getProperties()\n\t\t{\n\t\t\tMap props = super.getProperties();\n\n\t\t\tif (props == null || props.size() == 0)\n\t\t\t\t{\n\t\t\t\t\tif (mManager != null)\n\t\t\t\t\t\tprops = ((JdbcUserManager) mManager).getUserProperties(this);\n\n\t\t\t\t\tif (props == null)\n\t\t\t\t\t\tprops = new HashMap();\n\t\t\t\t}\n\n\t\t\tsetProperties(props);\n\t\t\treturn props;\n\t\t}\n}\n


Note that the JdbcUser is actually NOT serializable, which prevents it being used in sessions and the like.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Looks like a lot of beurOOcracy to me
The question comes up: why did you need all that crap in the first place. It appears you replaced really bad crap with slightly less bad crap and claim victory.
________________
oop.ismad.com
New Not claiming "victory"
You asked why I would use O-R mapping. I stated that I would use it over JDBC for particular reasons, and over straight SQL for others.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Let's see your version, then.


Peter
[link|http://www.debian.org|Shill For Hire]
[link|http://www.kuro5hin.org|There is no K5 Cabal]
[link|http://guildenstern.dyndns.org|Blog]
New Re: response 2
I posted one I would like to see in a nearby message. The "GPA" one.
I'm talking about persistence, not reporting. Hammers for nails, screwdrivers for screws. I'd probably use a stored procedure to obtain a single number like that. But since you asked, Hibernate supports aggregates as well.

Float avg = single("select avg(grade) from (select avg(student.grades) as grade from Student student)");

Note the absence of a group by. Very similar, otherwise.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Re Re: response 2
Float avg = single("select avg(grade) from (select avg(student.grades) as grade from Student student)");


You are passing a string of an SQL-like query language, but it is not SQL. Is this correct? Why invent another query language that is sort of like SQL? People already know SQL. (I agree that SQL is not the ideal relational language, but until a better standard is established, it is good enough.)

I'm talking about persistence, not reporting.


I am not sure what you are getting at then. Note that data dictionaries make a nice place to put info about converting fields into data columns, such as DB column type, length limits, etc. Ideally that perhaps should be stored in the RDBMS schemas, but vendors don't support extending that stuff for some reason.
________________
oop.ismad.com
New HQL is a superset of SQL
HQL understands inheritance and polymorphism. Joins are made automatically based on foreign key references. You'll note the lack of a group by in the previous example; that is significant. It also allows selection of grouped bodies of data without specification:

select parent from Post; - selects all of the data as a Parent object, without needing to specifiy what that entails.

It allows formation of objects on the fly through the query language as well:

select new Foo(a, b, c) from Bar; - creates a new Foo object as a subset of a Bar object.

Queries without joins:

from Post as post where post.parent.subject like '%response%';

from Post as post where post.forum.board.owner = ?;

Note that, with caching, some of the above can be resolved entirely in memory without a trip to the database.

Test sizes of collections:

from Forum as forum where forum.posts[0].responses.size > 42; - find all forums where the first post in the forums has more than 42 responses.

Here's a good one from the Hibernate docs:
select cust\nfrom Product prod,\n    Store store\n    inner join store.customers cust\nwhere prod.name = 'widget'\n    and store.location.name in ( 'Melbourne', 'Sydney' )\n    and prod = all elements(cust.currentOrder.lineItems)\n\nvs.\n\nSELECT cust.name, cust.address, cust.phone, cust.id, cust.current_order\nFROM customers cust,\n    stores store,\n    locations loc,\n    store_customers sc,\n    product prod\nWHERE prod.name = 'widget'\n    AND store.loc_id = loc.id\n    AND loc.name IN ( 'Melbourne', 'Sydney' )\n    AND sc.store_id = store.id\n    AND sc.cust_id = cust.id\n    AND prod.id = ALL(\n        SELECT item.prod_id\n        FROM line_items item, orders o\n        WHERE item.order_id = o.id\n            AND cust.current_order = o.id\n    )\n






Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New re: HQL is a superset of SQL
Joins are made automatically based on foreign key references.


Some RDBMS SQL dialects provide this ability also I hear, but I have yet to try it.

Here's a good one from the Hibernate docs: ....


Hmmm. Interesting. It uses "dot paths", such as "store.location.name".

Anyhow, suppose this HQL is the greatest query language since sliced bread and really does isolate one from specific RDBMS vendors.

Couldn't one just use HQL in place of SQL in procedural code without the rest of the OR-mapper stuff? (Assuming ER info is given via meta data.)

You are doing a better job at selling a query language than you are at selling OR-mappers, and so far they generally seem like orthogonal things.
________________
oop.ismad.com
New re: HQL is a superset of SQL
The query language is integral to the O-R mapper, and vice versa, in that it returns objects.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Forced to use A to get B? Tsk tsk tsk. How MS of them.
________________
oop.ismad.com
New You miss the point, anyway.
HQL can be used against any database engine.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New I am not necessarily disagreeing with that here
I am only saying that a better and/or vender-neutral query language/system is or can be orthogonal to O-R mappers.
________________
oop.ismad.com
New Re: I am not necessarily disagreeing with that here
At this point, it is not orthogonal. It exists for Hibernate, and it was easy to write because of OO. If you disagree, prove me wrong. Otherwise concede the point.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New not my burden of evidence
It exists for Hibernate, and it was easy to write because of OO. If you disagree, prove me wrong. Otherwise concede the point.


By "easy to write", do you mean using the framework or making the framework?

You have the burden of showing something being "easy". Remember: "Equal, subjective, or unknown until proven otherwise". I can accept that my preferences may be purely a subjective mindfit. If you believe OO is some universal truth and/or a slum-dunk improvement, then it is your burden to show it.
________________
oop.ismad.com
Expand Edited by tablizer May 23, 2004, 12:10:06 AM EDT
New Wrong.
Hibernate exists. Your mythical über SQL doesn't. If your version is even as good, let alone better, then you need to show it. Otherwise it's vaporware.

Now go answer or concede the other points.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New exist != good
Hibernate exists. Your mythical \ufffdber SQL doesn't. If your version is even as good, let alone better, then you need to show it. Otherwise it's vaporware.


Mere existence does not necessarily lead to goodness. You need to explain why it is so good using code. Show me something that procedural or raw SQL MUST result in a mess with. Nor am I going to compete with an army of programmers to build a clone of Hibernate all by myself. That is not a realistic request. I can perhaps show specific aspects though.

And being DB-neutral is moot because you are tied to Hibernate in a similar way. You are applying a double-standard.
________________
oop.ismad.com
New Existence beats Non-Existence
New I've already shown you.
Go answer or concede the other points.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Hm. So I can make any claim and force you to prove me wrong?
You started this debate with some wild claims. Are you saying now "that was just subjective?"

Remember: "Equal, subjective, or unknown until proven otherwise".


Nice ideal. But they're in reverse order. If you want your claims to move from unknown/subjective to equal, the burden is on *you*. That's life. Suck it up.
New Actually, what he said was:
"You spend all your code translating back and forth between two discordant paradigms."

So he made a very specific claim in this instance. ;-)
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
Expand Edited by admin May 23, 2004, 10:53:33 AM EDT
New Persistence vs. reporting
Saving and retrieving students is persistence.

Performing aggregate queries on properties of students is reporting.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Re: response 3
If you talk directly to the database, you lose opportunities for caching the data closer to where it is used. You also lose opportunities for creating screens that collect changes serially, then post them to the database all at once.
I would like a more specific example.


Caching example: doing a direct select on the database every time you need user information prevents you from caching the user information in memory. This isn't so big a deal for something like FoxPro, but it is when the query is more expensive; ie. against a remote database. If you're constantly querying the users, just load them locally and don't go against the database. An O-R layer handles this transparently.

Serial changes with batch update example: a set of user preference screens with different properties on each page. The user can change the preferences individually, then when satisfied do a Save that saves all of the properties at once. If you're going directly to the database, you have no intermediary data representation to store the possibly temporary values.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
Expand Edited by admin May 22, 2004, 05:14:00 PM EDT
New Re Re: response 3
Caching example: doing a direct select on the database every time you need user information prevents you from caching the user information in memory.


If it is used often, then simply write it to a memory variable:
\n  // create user-info map array\n  userInfo = queryRow("select * from users where userId = %1", userID)\n

Things like this are used fairly often in web scripts where user authentication is in a standard include-file, for example. I don't see what the big deal is. Here is a more thorow example to clarify the context:
\n  // standard header include file\n  ...\n  userID = session('userID');\n  if (empty(userID)) {\n    loginScreen();\n    endScript();\n  } else {\n    // create user-info map array\n    userInfo = queryRow("select * from users where userId = %1", userID)\n  }\n  ...\n

The userInfo array is now available to the entire script. I suppose you could argue that the login screen and the array query may be redundant references to the User table, but the DBMS might already perform caching of such. In other words, the second time you reference a given record in a short period of time, the second request should be quicker because the DB caches it for a while. Further, if you have a middle-layer between the app and the DB, then things might get out of sync with the database, such as a user record being deleted because an employee is fired (for bashing OO). More things to go wrong and more time-out scenarios to test.

Serial changes with batch update example: a set of user preference screens with different properties on each page. The user can change the preferences individually, then when satisfied do a Save that saves all of the properties at once. If you're going directly to the database, you have no intermediary data representation to store the possibly temporary values.


Assuming a "real" GUI, that info stays on the screens until it is saved. The screen serves as the intermediary data hold in this case. When they press "Save" or "Ok", then it writes those fields to the tables. If they press "Cancel", then it doesn't. (A good screen system allows hidden fields also that can come in handy at times.)
________________
oop.ismad.com
New Caching
// create user-info map array
userInfo = queryRow("select * from users where userId = %1", userID)

That's not caching. Now show the code that checks to see if it's already cached, and if not, to retrieve it from the database. Because if you're just relying on the database to cache, and the database is on another machine, you have to wait for the information to come over the wire. With an in-memory cache, it's already there. The performance increase is substantial.

For most applications, out of sync data isn't a worry. Only if more than one application is modifying the data in question is that an issue. And if you have more than one application doing this, you can use distributed cache updates.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Re: caching
That's not caching.


Yes it is. If I need something often in a given task, then I save it in a memory variable. What is the big deal? You are creating a solution for a minor or non-existing problem it seems.
________________
oop.ismad.com
New Er, no it isn't.
Where's the code to update it when you change it? Where's the code that decides when to load it? All you're doing is loading the one set of values and then using them for a single render transaction. That isn't caching.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Serial changes
Assuming a "real" GUI, that info stays on the screens until it is saved. The screen serves as the intermediary data hold in this case. When they press "Save" or "Ok", then it writes those fields to the tables. If they press "Cancel", then it doesn't. (A good screen system allows hidden fields also that can come in handy at times.)
And then you have to copy that intermediary data to the update queries. With an O-R mapping layer, there is no reverse mapping step. As such, you are just poorly duplicating the O-R system with one-off field mappings and storage areas.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New "Bound" fields
And then you have to copy that intermediary data to the update queries. With an O-R mapping layer, there is no reverse mapping step. As such, you are just poorly duplicating the O-R system with one-off field mappings and storage areas.


That probably assumes some integration with the GUI system. It is sometimes called "bound" fields, or a variation of. Generally such a framework stores the database column name, and perhaps also entity or query name, in the screen widget definition. Then a standard set of operations can automatically create the SQL to populate and save the info.
________________
oop.ismad.com
New No, no integration.
Java Beans, mapped to fields. Automatic, and it doesn't care where the data comes from, or where it's going, like bound fields do. And that doesn't cover web applications.

So with a web application, you will have a reverse mapping step given your example. Yes or no?
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
Expand Edited by admin May 22, 2004, 07:52:15 PM EDT
New re: No integration
Java Beans, mapped to fields. Automatic, and it doesn't care where the data comes from, or where it's going, like bound fields do. And that doesn't cover web applications.


Somehow database columns have to be associated with screen widgets. Applications and frameworks cannot read minds. For one, it is often not a one-to-one correspondence so that we cannot just take a schema as-is and splash it on a screen. Perhaps such can serve as the starting point, but not the final.

So with a web application, you will have a reverse mapping step given your example. Yes or no?


Ideally there is a data-dictionary-like UI item table that has optional column names. When the screen is drawn, it uses those column names to populate the widget. And when it is time to save, the same column names are used to build the saving SQL (unless designated read-only).
________________
oop.ismad.com
New re: No integration
Somehow database columns have to be associated with screen widgets. Applications and frameworks cannot read minds. For one, it is often not a one-to-one correspondence so that we cannot just take a schema as-is and splash it on a screen. Perhaps such can serve as the starting point, but not the final.
Correct.

Ideally there is a data-dictionary-like UI item table that has optional column names. When the screen is drawn, it uses those column names to populate the widget. And when it is time to save, the same column names are used to build the saving SQL (unless designated read-only).
So this includes data caching, query caching, and so on like Hibernate does? You'll have to write it and show it to convince me that it isn't more bloated than the example I've already given.

Where's the bloat with O-R mapping? You haven't shown that, and therefore your claim is still bogus.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New So you want to see an Iwethey clone?

________________
oop.ismad.com
New I'd prefer you answer the points first.
But suits me. The new version, of course, not this one.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New We need code, not brochure-talk, to settle this
I will not match iwethey feature-for-feature because nobody is ever going to use it, since there is already one. But, I could create the basic functionality and then add specific features that you want to explore.
________________
oop.ismad.com
Expand Edited by tablizer May 23, 2004, 05:24:01 PM EDT
New Re: We need code, not brochure-talk, to settle this
The user create/login/edit functionality of the new site I linked should be sufficient. I'll refresh the version that's on the site.

Features it has:

User caching and on-demand loading of user preferences
Session variables linked by a cookie session ID
Anonymous users
Login required can be turned on declaratively by screen
Remote database (ie. no filesystem databases - this isn't a desktop app)
Internationalized message stores for field labels and errors
Full unit and regression testing

Since this is a practical example, use whatever toolkits you wish, and no whining thereof. I'm not interested in pie-in-the-sky "well, it COULD be like this" crap.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
Expand Edited by admin May 23, 2004, 06:37:27 PM EDT
New Is that part of iwethey?
________________
oop.ismad.com
New Yes.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New questions and comments
Off the top of my head, here is how I might approach some of these, in case anyone is interested. I also have some questions.

User caching and on-demand loading of user preferences


I am not quite sure what you mean by this. I would possibly use the dictionary-array approach I described a day or so ago.

Session variables linked by a cookie session ID


PHP has built-in session handling (although they keep changing it).

Login required can be turned on declaratively by screen


Not sure what you mean by this. Do you mean the administrator has a switch?

Internationalized message stores for field labels and errors


I would probably create some tables something like this:

Table: Messages
---------------
msgID // could be number or pneumonic
EnglishMsg

Table: Languages
----------------
langID
langDescript // example: Spanish, French, etc.


Table: LanguageMessages
-----------------------
msgRef
langRef
msg

I probably would not include internationalization in my actual example because implementing the above is pretty obvious. More info on speed issues and others at:

[link|http://www.c2.com/cgi/wiki?InternationalUiExample|http://www.c2.com/cg...nationalUiExample]

Note pseudo-code example at the very bottom.

Full unit and regression testing


Fluck that. This is a toy example.

Since this is a practical example, use whatever toolkits you wish


May put me at a disadvantage since there are not a lot of existing TOP toolkits out there. Self-fulfilling prophecy trick again, eh? You sneaky devil.
________________
oop.ismad.com
Expand Edited by tablizer May 24, 2004, 02:01:55 AM EDT
Expand Edited by tablizer May 24, 2004, 12:41:13 PM EDT
New Reading comprehension?
From [link|http://z.iwethey.org/forums/render/content/show?contentid=156520|http://z.iwethey.org...?contentid=156520] (what you are replying to):

Since this is a practical example, use whatever toolkits you wish, and no whining thereof. I'm not interested in pie-in-the-sky "well, it COULD be like this" crap

What Scott said that he didn't want is a pretty good description of what you actually provided.

Don't say, "Well you could do this." Either do it or shut up.

Regards,
Ben
To deny the indirect purchaser, who in this case is the ultimate purchaser, the right to seek relief from unlawful conduct, would essentially remove the word consumer from the Consumer Protection Act
- [link|http://www.techworld.com/opsys/news/index.cfm?NewsID=1246&Page=1&pagePos=20|Nebraska Supreme Court]
New What is your complaint?
I provided descriptions as a *bonus*. If you don't want to read them, then simply ignore them. If Scott does not want to hear "it could be like this....", then he can just plain simply bypass it. The Web is big. Ignore what you don't want.
________________
oop.ismad.com
New Why not eliminate everything that is only a bonus?
Oops, not much is left, huh?

While Scott's attempts to enlighten you sometimes are informative for the rest of us, the conversation long ago reached the point where you really need to put up or shut up. Considering that nobody has demonstrable work experience with the way that you think should work better, while many of us have experience with existing alternatives, the burden of proof is on you to show that it is possible. Not us.

In case you didn't notice, our experience tells us that the approach that you're suggesting will not scale development-wise. Perhaps we just misunderstand what you're suggesting. Perhaps we really do understand what you're suggesting, and our intuition is wrong.

So why not build your own version of part of IWETHEY? I think that it really would be informative to see how you would tackle it. But until you do that, watching your hands flap in the breeze is rather pointless on all sides.

Cheers,
Ben
To deny the indirect purchaser, who in this case is the ultimate purchaser, the right to seek relief from unlawful conduct, would essentially remove the word consumer from the Consumer Protection Act
- [link|http://www.techworld.com/opsys/news/index.cfm?NewsID=1246&Page=1&pagePos=20|Nebraska Supreme Court]
New Then don't bother.
User caching: the user information is cached locally, in RAM, for performance reasons. User properties (preferences) aren't loaded unless they're needed.

Declarative login checking: if I want to require a user to be logged in to reach a particular screen, I put: <ref bean="loginInterceptor"/> in that section of the config file, and the login is checked and redirected if necessary.

Unit testing: Toy examples don't prove anything. If you aren't going to write unit tests then you're not showing anything, because one of the hallmarks of ease of maintenance is testability. It would be real easy to glop together a bunch of crap in a single messy, unmaintainable file and declare "victory".

Toolkits: Again, if it's not something you can do today, what's the point? I work with today's tools. I get things done. You're telling me that my code is bloated compared to what you can do. Well, prove it or concede that it isn't. PHP is used by an awful lot of people and there is a large body of work out there providing libraries of useful things. And if what you need is so all-fired useful, write it yourself so you have it to use in the future, for crying out loud. Should be easy, right, since it's "TOP"?

Unsurprising, Bryce. When it comes down to it all you have is excuses. Do you go to your employers and say, "well, I could code it like this if I had the ÜberMegaTOP Toolkit, but we don't, so I'll have to do a crappy job"...?
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
Expand Edited by admin May 24, 2004, 08:27:08 AM EDT
New Fine. It is not "bloated". Just unknown.
User caching: the user information is cached locally, in RAM, for performance reasons. User properties (preferences) aren't loaded unless they're needed.


You are micro-managing how to design such an app. Putting the user preferences into a map array may take up far less space and time than your caching manager because cached info takes up space whether you use it later or not.

Declarative login checking: if I want to require a user to be logged in to reach a particular screen, I put: <ref bean="loginInterceptor"/> in that section of the config file, and the login is checked and redirected if necessary.


So, one could put a "loginOnly()" function at the start of any checked section/page. By not putting it in XML I also have smaller granularity options on where it is used. For example, maybe certain buttons don't show or have a different description if not logged in.

Toolkits: Again, if it's not something you can do today, what's the point? I work with today's tools. I get things done.


So do I. I have written an e-bay clone (more or less) in less than 7 weeks during the dot-com mayham.

When it comes down to it all you have is excuses.


You were the one who has been claiming OO is objectively better and then expect me to rewrite a whole Iwethey from scratch? I withdrawl the "bloated" claim for now. Feel better? However, that still does not make OO less bloated than p/r, only unknown.

BTW, you guys never countered my running-code toy example at:

[link|http://www.geocities.com/tablizer/chal06.htm|http://www.geocities...blizer/chal06.htm]

I was first with the coded challenge, and now you are trying to trump it with your own. If OO cannot do that better, I would like to know why. If it's because it is a toy example instead of a real one, then describe how it differs from a real one that prevents OO's benefits from showing up.

"well, I could code it like this if I had the \ufffdberMegaTOP Toolkit, but we don't, so I'll have to do a crappy job"...?


Sure, if they pay me, I will work with lame tools. It may slow me down compared to a good TOP system, but that is life. Same reason we live with Microsoft. I tend to think that favorite paradigms and tools are subjective. Studies by Ed Yourdon seem to suggest that using tools that one is comfortable with is more important for productivity and quality than selecting tools based on what is popular.

Show me slam-dunk evidence that OO is better, and I will look into it more. Most reasons given for OO are fuzzy-zenny, and make tradeoffs that the claimers are not aware of or conveniently ignore. For example grouping by noun helps noun-oriented changes, but un-helps task-oriented changes. Plus, the reasons everybody gives why OO is better differ. Some say polymorphism off of "subtypes" or variations is the main power of OO. Others who use more delegation disagree. Nobody has been able to clearly "encapsulate" the benefits of OO. All I get is, "it is j..j..j..just b..b..b..better, and if you were smart like me, you would see it."
________________
oop.ismad.com
New That's all I needed.
You were the one who has been claiming OO is objectively better and then expect me to rewrite a whole Iwethey from scratch? I withdrawl the "bloated" claim for now. Feel better? However, that still does not make OO less bloated than p/r, only unknown.
It seems to me the claim under discussion in this thread was "O-R mappers bloat your code". Now that you've admitted that they don't, we can put it to rest.

Although I'll note that old habits apparently die hard. You're still weaseling. Either the code is bloated compared to how you would do it, or it isn't. If you're not willing to provide an example, the conclusion to be drawn is "Bryce can't provide an example", not "the status is unknown." You say it's bloated, prove it. Otherwise it isn't.

So do I. I have written an e-bay clone (more or less) in less than 7 weeks during the dot-com mayham.
Then stop whining about toolkits. You must have used something to do that.

BTW, you guys never countered my running-code toy example at:

[...]

I was first with the coded challenge, and now you are trying to trump it with your own. If OO cannot do that better, I would like to know why. If it's because it is a toy example instead of a real one, then describe how it differs from a real one that prevents OO's benefits from showing up.
1) I'm not in the habit of reading your website in the off-chance that you've provided something for me to do and 2) I'm not interested in toys, which you admit it is. Here's an example that does a real-life thing. If you think you can do better, then have at it. Otherwise shaddap.

[edit: removed the broken "challenge" link]
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
Expand Edited by admin May 24, 2004, 03:12:45 PM EDT
New Probably not telling you anything you don't already know...
...but that example was originally started by Jim Weirich on Freep's OOP board. JohnU also got involved. Of course, since EZBoard decided to shut down the inactive boards, we don't have any extant to refer to.

The reason I like the EZBoard example is (a) it's working (or soon to be working) code - the code can be objectively tested for performance and features; (b) it's something that we share in common and can immediately reap the benefits of any new ideas.

So, yes, let's dispense with code fragments and toy code.
New I take it you mean...
... "IWETHEY example", and not "EZBoard example"?
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Yep = That's what I meant
The reporting example was fine, it's just that there was no measurable way to run the code and verify for correctness and performance.
New Re: Probably not telling you anything you don't already know
...but that example was originally started by Jim Weirich on Freep's OOP board

Actually, the problem was introduced by someone else (JohnU perhaps?). Bryce actually wrote some (non-working) psuedo-code for it. All I did was translate Bryce's non-working psuedo-code into working Ruby code. Then I refactored to a better written procedural version and finally made it more flexible by introducing some polymorphism.

I always thought the problem description was a little screwy (I never really understood the need for some the the requirements), but at least we had some form of code from Bryce to compare to. And the OO code compared very favorably with the procedural version (e.g. comparable code sizes (no bloat), polymorphism without taxinomy).

At least, that's how I remember it.
--
-- Jim Weirich jim@weirichhouse.org [link|http://onestepback.org|http://onestepback.org]
---------------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
New My memory is too taxed
Not sure why I thought you initiated the sample. But your recollection does sound about right.

Sure wish we hadn't lost the EZBoard archives. For that matter, I wish Freep would come visit every once in a while.
New Memory Lane
I always thought the problem description was a little screwy (I never really understood the need for some the the requirements)


We kind of never agreed on the scope.

And the OO code compared very favorably with the procedural version (e.g. comparable code sizes (no bloat), polymorphism without taxinomy).


If I remember correctly, you implemented a different set of features than mine, so that we really couldn't compare code-to-code for many parts, but rather focused on the architecture issues.
________________
oop.ismad.com
New re: That's all I needed.
It seems to me the claim under discussion in this thread was "O-R mappers bloat your code". Now that you've admitted that they don't, we can put it to rest.


I didn't say that they don't. I just don't have any comparative evidence to offer youses right now.

I am curious though about what percent of self-declared OO proponents prefer O-R mappers. Many have lots of complaints.

"Bryce can't provide an example", not "the status is unknown." You say it's bloated, prove it. Otherwise it isn't.


False dichotomy. The answer to "is A > B" is Null at this point.

Otherwise shaddap.


Okay. After addressing some ongoing subissues, I will shut up about O-R mappers until new evidence arises.
________________
oop.ismad.com
New re: That's all I needed.
Given that the evidence so far has either been conceded or unanswered by you, I'd say "isn't" is a lot closer to the current state of affairs than "null". Of course, you will never admit that, so I'll take a "shaddap". I have no doubt that you'll sit on this for a while and then trot out, "youses never proved it wasn't bloated!" at some point in the future, so I'm calling pre-foul now so it doesn't happen.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Caching
You are micro-managing how to design such an app. Putting the user preferences into a map array may take up far less space and time than your caching manager because cached info takes up space whether you use it later or not.
The caching manager is generic. I don't need special one-off caching code all over the place. And it seems to me that you've always been the "machines are fast, programmers aren't, optimize for the programmer" champion. Why the sudden reversal?

Regardless, I listed it as a feature. If you believe you have a better way of doing it, then do it that way. I'll warn you, though, that the caching speeds the app up considerably over loading it from the database for every request.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Login checks and declarative processing
So, one could put a "loginOnly()" function at the start of any checked section/page. By not putting it in XML I also have smaller granularity options on where it is used. For example, maybe certain buttons don't show or have a different description if not logged in.
Which is what my code does in addition to the generic declarative checks. So your method is not as functional. If I want to have the entire application protected, that's one change in the config file. Or perhaps every page that has the word "secure" in the URI. Less work on average.

But I don't care how you do it, I'm just telling you what needs to be done. Some pages are protected, others aren't.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New re: Login checks and declarative processing
If I want to have the entire application protected, that's one change in the config file.


In most web apps I have a standard "include" file. If I want the check applied to all pages, I simply put it there.

Or perhaps every page that has the word "secure" in the URI.

\n  // standard header file\n  ....\n  if (contains(selfURI, 'secure')) {\n    performCheckFoo(...)\n  }\n

________________
oop.ismad.com
New re: Login checks and declarative processing
And if you decide to move that include file? Or rename it? Don't say it doesn't happen, because it does. What if a developer forgets to include the check file in his page? What if two different clients share the same code, but run it locally and want to configure it differently?

Your solutions always "work" for suitably limited scopes. I'll take the solution that's more globally applicable, thank you.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New re re: Login checks and declarative processing
And if you decide to move that include file? Or rename it? Don't say it doesn't happen, because it does. What if a developer forgets to include the check file in his page?


Then most pages will probably not work because a lot of stuff tends to depend on it for things like database handles.

What if two different clients share the same code, but run it locally and want to configure it differently?


A "split or share" decision is part of any such endevour. Computers can't read minds. If the criteria for triggering a given check changes, we simply change the criteria. Boolean expressions are usually more powerful than subclassing because we don't have to try to cram it into a tree shape and can more easily have orthogonal factors involved. Subclassing tends to puke and squirm when dealing with orthogonal factors.
________________
oop.ismad.com
New Re: Login checks and declarative processing (new thread)
Created as new thread #156712 titled [link|/forums/render/content/show?contentid=156712|Re: Login checks and declarative processing]
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New I18N
All that link to the Internation UI Example showed was your inability to grasp the issues. "Bottom" is right... using a database over text files gives you no benefits, and results in a loss of efficiency.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New You are WRONG!
All that link to the Internation UI Example showed was your inability to grasp the issues.


Name calling? I don't appreciate that in the slight. I take big offense to that. Fuck you! If you have slam-dunk evidence then show it shove it!

"Bottom" is right... using a database over text files gives you no benefits, and results in a loss of efficiency.


If one has the option of using tables to generate "resource files" or whatever you want to call them, then the compiler does NOT CARE where they came from. It is not going to say, "Oh, these resource files were auto-generated from DB tables; therefore, I will run them slower". That is outright silly! That is a PHB-style mental error.

I personally don't want to manage boatloads of messages as programming language files. Databases were created to help people track and manage boatloads of attributes, and that is just what international message info is. You are not going to tell me how to best manage information that I have to work with. Sure, a boss can dictate to me how to organize such info, and can even dictate to me how to organize my desk and pencils and paperclips. But, that does not necessarily make me more productive. Having them in tables allows one to sort by language, sort by message (ID), search for similar messages, print reports that non-programmers understand, etc. The presentation becomes untied to a programming language grouping or file organization. Sure, if it is a small application and there are only a few target languages, then editing within code files directly is fine. The bottom line is that code makes a shitty database.
________________
oop.ismad.com
Expand Edited by tablizer May 24, 2004, 02:15:41 PM EDT
New My my, I touched a raw nerve, apparently.
Where's the name I called you?

From the link:
Top: I am trying to think fairly large-scale here. What if "last" is used to mean both "previous" and "final" in different circumstances in the application?

Bottom: The word "last" can be used in many different circumstances in the application.

Top: A simple content look-up will not work.

Bottom: It will and it does. The word "last" isn't looked up by itself. The phrases "Enter last name:" and "Your glory shall last" each have their own separate translation. It doesn't matter that the same word appears in each English version.
It's pretty plain to me that you don't understand the issues here. Hence your confusion in the conversation you linked. How is this name calling?

I personally don't want to manage boatloads of messages as programming language files.
Neither do I. That's why I use resource files.

You are not going to tell me how to best manage information that I have to work with.
And you have done how many internationalized sites? I thought so. Yet you still feel qualified to tell everyone that your approach is so much better, even though it just solves problems that don't exist. "Bottom" is right. People don't need the sorts of "reports" you're talking about.

Having them in tables allows one to sort by language,
Er, and this can't be done with resource files for what reason?

sort by message (ID),
Why would anyone want to do this? You don't understand the problem set.

search for similar messages,
grep is your friend.

print reports that non-programmers understand, etc.
What kind of reports? This stuff simply isn't needed, and your over-engineered "solution" is more work for no gain.

code makes a shitty database
And databases make shitty code.

Now change your tone or this conversation is over. I've been perfectly civil to you and I don't appreciate your response. You're acting like a sore loser.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Grep is no substitute for clean, normalized data
It's pretty plain to me that you don't understand the issues here.


The context of that has appearently been deleted. Some were proposing translations using phrase look-ups. Even the links given did not use direct phrase lookups.

How is this name calling?


You accused me of "inabability to grasp the issues" without giving specifics. Even if true, the diplomatic way to say it is, "I beleive you are incorrect with regard to point X" rather than some sweeping generalization. Your people skills are even worse than mine, and that is saying something.

I've been perfectly civil


Bull. See above. Even if you think somebody is a total retard, it is improper to inform them of such judgement. One should point out specific things to complain about, not sweeping or vague generalizations.

If you know of a specific use-case that busts my proposed solution, you are by all means welcomed to produce it.

grep is your friend.


That is a hacky approach. Tables are safer.

Neither do I. That's why I use resource files.


Hardly better than source code files.

Why would anyone want to do this? You don't understand the problem set.


That is nature of the biz world: you cannot predict ahead of time how somebody is going to want to see/query something.

And databases make shitty code.


Translation lookup tables are not "code". Even the VB resource file example calls them "tables".
________________
oop.ismad.com
New Re: Grep is no substitute for clean, normalized data
That is a hacky approach. Tables are safer.
That is a general statement. Provide specifics.

Hardly better than source code files.
In what way? They're a specific solution for a limited problem.

some.string=The specific string for a message.

How is the above "hardly better than source code"?

I'll go you one better, in fact: how do you maintain database information over revisions? Keeping this in the database isn't sufficient when you have several database environments (Dev, Test, QA, Prod for example). Text resource files are amenable to revision control via common source code control tools.

Translation lookup tables are not "code".
And neither are resource files.

That is nature of the biz world: you cannot predict ahead of time how somebody is going to want to see/query something.
Especially if you've never done an internationalized application, which I'm guessing (by your non-response) that you haven't. Those who have understand that this simply isn't a requirement. You're inventing problems in order to provide your "solution". And since your solution adds extra complexity in the form of database access (or code generation) for no material gain, it is inferior.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Depends on the scale
{That is a hacky approach. Tables are safer.} That is a general statement. Provide specifics.


You generally don't have to parse to isolate the "atoms". Unless you always provide a perfect parsing specification, there is a chance of getting it wrong. The "walls" are predefined for us so that we don't have to find them over and over.

I'll go you one better, in fact: how do you maintain database information over revisions? Keeping this in the database isn't sufficient when you have several database environments (Dev, Test, QA, Prod for example). Text resource files are amenable to revision control via common source code control tools.


I will agree that the existing crop of revision control tools are designed for files and not databases (although I have not done a survey yet). However, tables make it easier to roll-your-own. Plus, one can have more control over individual messages. See below.

I am just too damned far ahead of my time :-)

Especially if you've never done an internationalized application, which I'm guessing (by your non-response) that you haven't. Those who have understand that this simply isn't a requirement. You're inventing problems in order to provide your "solution". And since your solution adds extra complexity in the form of database access (or code generation) for no material gain, it is inferior.


No, I have not done formal internationalization. But, how large was the project(s) you did? A tablized solution probably would not be practical unless you have say 20+ languages and 1000+ messages (per lang). Files are fine for smaller stuff. I never disputed that here.

I am pretty sure there is a size-point in which you agree that files won't cut it anymore. For example, suppose most of the translators work offshore (which is expected for language translation). One may want a web-site where they log into and review and change messages. Doing that at a file granularity is a bit messy. Through such a portal we can fairly easily track which messages were changed by who and when. That can be done with files, but it takes a lot of Diff commands.

You also make it sound as if tables are hard to use and bulky for internal stuff. Somebody used to XBase stuff will generally disagree.
________________
oop.ismad.com
New You've never used CVS either, have you?
New No, only MS sourcesafe
________________
oop.ismad.com
New *shudder*
I used Source"Safe" once. Just once. It ate the repository. What a piece of cack that program is.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Not my pickings
________________
oop.ismad.com
New Re: Depends on the scale
You generally don't have to parse to isolate the "atoms". Unless you always provide a perfect parsing specification, there is a chance of getting it wrong. The "walls" are predefined for us so that we don't have to find them over and over.
foo.bar=Foo the bar\nmoo.gar=Moo the gar
grep "foo.bar" finds all instances of the "foo.bar" message. You're inventing problems where none exist.

I will agree that the existing crop of revision control tools are designed for files and not databases (although I have not done a survey yet). However, tables make it easier to roll-your-own. Plus, one can have more control over individual messages.
I'm not interested in "rolling my own". I'm interested in getting work done. If your approach provides no tangible benefits, and in fact has some disadvantages as I have named, why in the name of seven Hades would I "roll my own" just to get to the same level of functionality I already had?

I am pretty sure there is a size-point in which you agree that files won't cut it anymore.
I don't see why. One file per message set per language. No overhead. If it's farmed out, give them the English version and say, "translate this". Once the bulk job is done, changes will be minor and are best handled through existing revision control tools. And I certainly wouldn't give a bunch of people located off-shore access to a database used by the production system.

The management becomes harder the larger the system becomes, mainly due to the multiple environments I mentioned.

You also make it sound as if tables are hard to use and bulky for internal stuff. Somebody used to XBase stuff will generally disagree.
Something that large isn't using XBase, I can guarantee you. And they are bulkier and harder to use than resource files.

Here's an example:
\n<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">\n\t<property name="basename"><value>Messages</value></property>\n</bean>
That's what I do in the config file to load my resource files. When I want to use a message, I do this:
<fmt:message key="some.key"/>
That inserts it into the JSP file. Whoopdee doo, that's so incredibly hard. I must be high if I think that's better than a bunch of SQL select statements.

And calling into a remote database for thousands of strings isn't practical. And if you cache them, that's more coding and database maintenance overhead just to match the same functionality provided by resource files.

Pre-compiling involves the database in the compilation step, which is also useless overhead and harder to manage.

Have you actually worked on a large-scale system? Say something with a few hundred tables, a million lines of stored procedures, and millions of rows of dynamic data? The kind of thing you're proposing introduces unneeded, unwanted complexity into an already complex system.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New no no no
grep "foo.bar" finds all instances of the "foo.bar" message.


Yes, but if you have "x = 'my foo bar is here'", it may also pick up that message.

and in fact has some disadvantages as I have named


Very minor.

And the message tables can be used with other languages and systems.

Once the bulk job is done, changes will be minor and are best handled through existing revision control tools.


In my experience, vast change requests may come out of left field so that there is a lot of rework to be done.

And I certainly wouldn't give a bunch of people located off-shore access to a database used by the production system.


You don't give them database access, only access to a web application. And, it does not have to be a production system. Besides, why is file access safer than database access? A file system *is* a database, just not a relational one.

Something that large isn't using XBase, I can guarantee you. And they are bulkier and harder to use than resource files.


I am not necessarily talking about the production application language. One can build tools in a different language than final applications.

I must be high if I think that's better than a bunch of SQL select statements. And calling into a remote database for thousands of strings isn't practical.


You got it all wrong. Each message does not necessarily issue a Select statement.

Have you actually worked on a large-scale system? Say something with a few hundred tables, a million lines of stored procedures, and millions of rows of dynamic data? The kind of thing you're proposing introduces unneeded, unwanted complexity into an already complex system.


So we should chuck databases and go back to flat files to manage everything? How 1960's of you. The bigger the project, the more a database HELPS! Keeping tons of attributes in a bunch of hard-to-query and hard-to-find flat files is really annoyining.

How about this. We start out with a file-based approach. If message management becomes a headache, then we DB-tize the config file generation. Deal?
________________
oop.ismad.com
New Re: no no no
Yes, but if you have "x = 'my foo bar is here'", it may also pick up that message.
grep "foo.bar="

And the message tables can be used with other languages and systems.
And a text resource file can't? You're stretching.

In my experience, vast change requests may come out of left field so that there is a lot of rework to be done.
Ah, your vast experience doing internationalized systems. I see.

You don't give them database access, only access to a web application. And, it does not have to be a production system.
Ah, so now you're maintaining TWO databases for the sake of this labor-saving scheme of yours. Got it.

Besides, why is file access safer than database access? A file system *is* a database, just not a relational one.
Because the changes are being checked in and managed by me, not the guy on the other end of the wire whose only talent is converting English into Swahili.

You got it all wrong.
No, it's called "covering all bases" since you're being so vague about "might" and "doesn't necessarily" and so forth. You oh-so-conveniently didn't quote "And if you cache them, that's more coding and database maintenance overhead just to match the same functionality provided by resource files." So just exactly how does this system of yours work? Or haven't you thought it through properly? Does it issue a single select? "Not necessarily." Does it cache them on the first hit? Who knows. Does it cache them for each page? Can't tell you.

So we should chuck databases and go back to flat files to manage everything? How 1960's of you. The bigger the project, the more a database HELPS! Keeping tons of attributes in a bunch of hard-to-query and hard-to-find flat files is really annoyining.
No, but they're damn nifty for internationalized messages. How very binary of you.

"hard to query" Er, no. Got grep or find? Got an editor? Everyone does. Better that than "oh, to work on the messages you need to set up ODBC like so, and install Access, and search for them here like this. Oh, wait, you wanted to see the messages in QA, not DEV? Well, you need a different ODBC source then..." Seems to me the database version is a lot more of a pain in the ass for someone who just wants to edit a bit of text.

"hard to find" Care to back this up? They're right there in the same place as the JSP files that use them, as opposed to way off in database land, completely unrelated to the code that references the messages. Seems to me the database version is a lot more of a pain in the ass for someone who just wants to edit a bit of text.

How about this. We start out with a file-based approach. If message management becomes a headache, then we DB-tize the config file generation. Deal?
What's this "we", Kemosabe? Message management hasn't become a headache yet. You've not demonstrated that it will be, and given that you have no experience in the matter... and since I'm working on a system right now that has nearly 2000 similar text resource files, I'll keep my own counsel on that one, capicé?
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Doing my part to promote right shifting
Perhaps you've already explained in this thread and I missed it, but.....

Was wondering why your putting internationalization in the board. I've been putting off internationalization in my current app, mostly due to Sarbanes-Oxley being U.S. centric. Sooner or later I'm going to have to tackle it, as some of our customers have to get sign offs from far away lands (europe, china, etc). So I fully understand that it is a requirement for a lot (if not most) business apps these days.

Just wondering what you are trying to leverage on zIWETHEY?

(For example, does it make Nadsat or Guido easier to implement?)
New "Oh goody, a new framework for xmas!"
Was wondering why your putting internationalization in the board.....Just wondering what you are trying to leverage on zIWETHEY?


Isn't it obvious?: To make competing with his features harder for me. His whole life revolves around kicking p/r's ass :-)
________________
oop.ismad.com
New Re: "Oh goody, a new framework for xmas!"
His whole life revolves around kicking p/r's ass
Not really. I do that before breakfast and then go on to get real work done the rest of the day... ;-)
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Internationalization (new thread)
Created as new thread #156729 titled [link|/forums/render/content/show?contentid=156729|Internationalization]
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New admin
grep "foo.bar="


That's the point: you have to keep sticking conditions in there as you encounter problems. And, what if there are spaces around the equal sign? A bigger and bigger regex for each new variation encountered.

And a text resource file can't? You're stretching.


I know that most languages can reference the common RDBMS. I don't have to keep reinventing the same parsing in different languages.

Ah, your vast experience doing internationalized systems. I see.


Just because you've done one or two does not mean you have encountered all possible request permutations.

Ah, so now you're maintaining TWO databases for the sake of this labor-saving scheme of yours. Got it.


Coupling to your favorite everchanging frameworks is not always labor-free either.

Because the changes are being checked in and managed by me, not the guy on the other end of the wire whose only talent is converting English into Swahili.


Well, then it is not a "large project".

So just exactly how does this system of yours work? Or haven't you thought it through properly? Does it issue a single select? "Not necessarily." Does it cache them on the first hit? Who knows. Does it cache them for each page? Can't tell you.


The optimum solution depends on a lot of things, for example whether we are using a dynamic or static language, whether performance is more important than developer labor, whether it is web-based, etc.

"hard to find" Care to back this up? They're right there in the same place as the JSP files that use them, as opposed to way off in database land, completely unrelated to the code that references the messages.


So lets put everything in code and forget databases. New employee? Don't put them into a database, but rather code up an XML file. Replace Oracle with XML. Yeah, that's progress.

________________
oop.ismad.com
New Resource files (new thread)
Created as new thread #156741 titled [link|/forums/render/content/show?contentid=156741|Resource files]
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Re: response 4
That is called a "stored procedure". But, if it is DB-neutral, what are you sending to the DB itself? Not SQL?
You still have the call to the stored procedure to parse. What many caching query libraries do is create a transient stored procedure transparently, then use it with supplied parameters whenever that query is called again. This portion depends on the facilities of the underlying database, which, I would point out, I don't have to worry about because I'm using a mapping layer. I get as much caching as can be supported without any changes, no matter what back end is doing the work.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Lock-in is lock-in
This framework you use does not sound like a trivial peice of software. Again, you seem to be trading DB vendor lock-in for OR-mapping framework vendor lock-in. The same evil, but with yet more layers.
________________
oop.ismad.com
New Query caching is a feature of JDBC
The point being, which you are trying to avoid, is that this is something you get that straight SQL does not provide. Don't try to change the subject to "lock-in" now. So do you agree or not, query caching is a good thing to have?
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Yes
So do you agree or not, query caching is a good thing to have?

All else being equal, sure.
________________
oop.ismad.com
New Re: response 5
I note that you omitted: Dual layer caching, Lazy instantiation, Database/data source independence
I suspect the first 2 are something specific to an OO-centric design.
Dual layer caching refers to in-memory caching of database results. Lazy instantiation refers to only retrieving results as they are actually required.

The last one was already discussed. I doubt one can nicely put nearly all SQL behind an API.
Your doubts arise from ignorance.

And if possible, I doubt only OO can do it well.
Weaseling again. Your statement, once more: "You spend all your code translating back and forth between two discordant paradigms."

Where's the bloat?

Still waiting...
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
Expand Edited by admin May 22, 2004, 07:49:36 PM EDT
New Most of those are problems, not solutions.
Databases provide more than just "storage".... If you use them ONLY for storage, you are wasting them and probably reinventing many of these things from scratch or getting them from the OR tool. Thus, the OR tool becomes a half-ass database of it's own.


The OR tool takes over some of those functions because databases are themselves "half-ass" at many of them.

Example:

* Persistence
* State management
* Backup and replication of data


I fail to see how these 3 are different than the term, "storage". But I'll let you have a little padding in your list. Part of my point is that different DB's do replication (for example) differently, and deployers should be free to select a DB for such reasons. Instead, we have developers selecting which DB's they will support.

* Query languages or query ability
* Data computation/processing (such as aggregation and cross-referencing)
* metadata repository
* Access security
* Data rule enforcement or validation
* Multi-user contention management and concurrency (locks, transactions, rollbacks, etc.)
* Multi-language and multi-application data sharing


The last one is the only point I'll consider (multi-language). This is why, for example, many application-layer providers have drunk the XML Kool-Aid lately (although I think XML is overkill). Anyway, many O-R producers these days provide a socketed app that can serve multiple languages, or a DLL, or shared memory, or just connect components from dissimilar languages. It's not a hard problem--there are lots of options.

For the rest, I find it extremely cumbersome to perform any of those tasks within the data store. All of those concern business policies, which are modified often enough that they should be in application-level code. As businesses change, queries change, metadata changes, and security requirements change. Databases are well-known for sucking golf balls when these changes occur--they either:

1) force such concerns into SQL, which isn't powerful enough to handle it, or

2) introduce their own proprietary layer of "metadata", which an application developer then has to write a wrapper for anyway--we're back to the problem of writing Yet Another Wrapper module for each database we wish to support with our app.

both of which lead to

3) hiring another warm body just to manage "the database".

Placing these tasks into an app framework reduces cost, maintenance staff, and time-to-market. To repeat a mantra, "databases should be a commodity by now". If you disagree, then you've been suckling at the DB vendors' teats for too long. Separation of concerns is a Good Thing--DB's rock at storage, and suck at all those other things, doubly so in a hetero environment. One of the reasons they suck is that they try to be all things to all consumers.
New intense DBA and RDBMS bashing
I fail to see how these 3 are different than the term, "storage".


How exactly do you define "storage" then? Disk? RDBMS don't have to be based on disk. Many of them cache stuff in RAM, automatically. When I do an UPDATE query, I don't have to care about disks and caches in most cases. It is you OO'ers that seem to make a distinction between disk and RAM "state".

force such concerns into SQL, which isn't powerful enough to handle it


SQL is not meant to do *all* processing, nor does it have to in order to be useful. It is called "divide-and-conquer": The DBMS does what it does best and let code do the rest. It is not an all-or-nothing thing nor does it have to be.

Perhaps you just don't know how to use RDBMS effectively and would rather reinvent a tool rather than use one.

introduce their own proprietary layer of "metadata", which an application developer then has to write a wrapper for anyway--we're back to the problem of writing Yet Another Wrapper module for each database we wish to support with our app.


Like I said elsewhere, I am not yet convinced that an API can nearly completely wrap SQL except for the trivial. Even if one could, it does not have to be an OO wrapper and does not have to be an OR-mapper. A better solution from an app developer's perspective would be to target a specific dialect of SQL and then have something translate it to specific vendor dielects.

hiring another warm body just to manage "the database".


DBA's often do useful things such as tune performance, manage backups, make sure good schema design is used, apply data integrity rules, and that normalization is applied. Good normalization is pretty much the same as "once-and-only-once", which should be done on ANY "noun model".

Most biz data is used by multiple applications in multiple languages. Either you maddly replicate all over the place, or you hire SOMEBODY that does DBA-like work to manage the central repository. Whether you give them another name or divide up those tasks amoung app developers, somebody has to do it.

Placing these tasks into an app framework reduces cost, maintenance staff, and time-to-market.


If you want RAD and don't give a crap about sharing the data with other systems and tools (for whatever odd reason), then use FoxPro with native DBF files.
________________
oop.ismad.com
Expand Edited by tablizer May 22, 2004, 07:36:21 PM EDT
New ..heh. Only because they deserve it. ;)
Like I said elsewhere, I am not yet convinced than an API can nearly completely wrap SQL except for the trivial. Even if one could, it does not have to be an OO wrapper and does not have to be an OR-mapper. A better solution from an app developer's perspective would be to target a specific dialect of SQL and then have something translate it to specific vendor dielects.


"better solution" because...? Status quo?
New re: Only because they deserve it.
"better solution" because...? Status quo?


Better solution because:

1. A good many developers already know SQL.

2. They don't have to deal with Yet Another Layer of APIs.

A vendor-neutral SQL translator can solve most or all the problems you claim direct SQL causes.
________________
oop.ismad.com
New I assume you already expect my response:
1. A good many developers already know OO.

2. They don't have to deal with SQL at all.

Your solution has application developers working with at least two layers, where my solution has only one layer. *Framework* developers may deal with two, but not *application* developers. This is what we mean by making the storage layer "transparent".
New I will agree that...
RDB fans tend to dislike OO and OO fans tend to dislike RDB's. They have been fighting on places like C2 Wiki long before I made my presence known there. OO fans tend to be code-centric thinkers and relational fans tend to be declarative (data-driven) thinkers.

Note that liking OO does not mean you automatically know a given O-R framework off the mark.
________________
oop.ismad.com
New I've never claimed that _every_ O-R mapper is chicken soup
Note that liking OO does not mean you automatically know a given O-R framework off the mark.


True, but when it's bloody simple... the Dejavu "O-R framework" comes down to:

1. Units, which you subclass for your core data, and which only have three methods most app developers will use:
    a. set_property (a classmethod)
    b. memorize (makes a new Unit object persistent)
    c. forget (destroys a Unit)

and

2. A namespace, which manages Units. That only has three methods:
    a. associate(class, key, far_class, far_key), which oddly enough associates two Unit classes;
    b. recall(class, expression), and
    c. unit(class, ID=?), both of which retrieve Units

and

3. logic.Expression(<Python expression>), which makes an object out of an expression.

...all Python, all the time. I admit that if you've done all your OO in Java, then you have to learn Python to use Dejavu. But c.l.p. is replete with stories of programmers, both novices and experts, picking up 95% of Python within a week or two--it's designed to be easy to learn, natural, and expressive.

I don't see any of this as "bloatware".
New Most people can at least read Python within 5 minutes.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New Whatever
________________
oop.ismad.com
     Have I mentioned lately that Python is BITCHIN??? - (FuManChu) - (167)
         The solution is to toss OO to begin with, not Python - (tablizer) - (166)
             Re: The solution is to toss OO to begin with, not Python - (admin) - (11)
                 not today -NT - (tablizer) - (2)
                     *BLAM BLAM* *VROOOOOooooommm.....* -NT - (pwhysall) - (1)
                         and when you do the same? -NT - (tablizer)
                 Bloat explanation - (tablizer) - (7)
                     Not what I meant. - (admin)
                     That's a very table-centric point of view - (FuManChu) - (5)
                         Of course. Tables rock. Code is ugly. - (tablizer) - (4)
                             Snort. - (FuManChu) - (1)
                                 Re: Snort - (tablizer)
                             So now you're down on "skinny" tables? - (ben_tilly) - (1)
                                 Re: So now you're down on "skinny" tables? - (tablizer)
             Not sure what you're pushing for. - (FuManChu) - (153)
                 Software engineering is gambling - (tablizer) - (152)
                     The only thing this app does is business modeling. -NT - (FuManChu) - (151)
                         I meant showing me code, not anecdotes -NT - (tablizer) - (150)
                             Ironic, considering how much code *you* have shown... -NT - (ben_tilly) - (9)
                                 Wonder how the L Compiler is getting on? -NT - (pwhysall) - (6)
                                     It's Late. - (admin) - (5)
                                         I was wondering where the L it was. -NT - (pwhysall)
                                         The P game - (tablizer) - (3)
                                             Re: The P game - (admin) - (2)
                                                 you still have no evidence of betterment - (tablizer) - (1)
                                                     No, you compare it. - (admin)
                                 The burden of evidence is on you - (tablizer) - (1)
                                     And what claim did I ever make? - (ben_tilly)
                             Well, here's the thing - (FuManChu) - (139)
                                 Unicorns - (tablizer) - (138)
                                     OT: Have you been reading Groklaw tonight too? - (Another Scott)
                                     General description - (FuManChu) - (136)
                                         SQL wrapper? - (tablizer) - (135)
                                             Generic SQL wrapper API - (admin) - (30)
                                                 I see bloated people - (tablizer) - (29)
                                                     Er... - (admin) - (19)
                                                         re: Er... - (tablizer) - (18)
                                                             Nice attempt - (admin) - (17)
                                                                 re: Nice attempt - (tablizer) - (13)
                                                                     re: Nice attempt - (admin) - (12)
                                                                         Forgot to add: - (admin)
                                                                         Aieee! Actual code! HOW DARE YOU!!! -NT - (pwhysall) - (10)
                                                                             Making it interesting - (ChrisR) - (9)
                                                                                 Heh. I think Bryce would rather have someone else write it - (FuManChu)
                                                                                 Don't you know? - (Arkadiy)
                                                                                 Putting words in my mouth - (tablizer) - (6)
                                                                                     Actually, what you said was: - (admin)
                                                                                     Re: Putting words in my mouth - (admin)
                                                                                     Code Talks. Bryce Walks. - (ChrisR) - (3)
                                                                                         I shall consider it -NT - (tablizer) - (2)
                                                                                             Thanks. - (ChrisR)
                                                                                             If you don't... - (admin)
                                                                 RE: Are you willing to admit this yet? - (ChrisR) - (2)
                                                                     Even OO fans are mixed about OR-mappers - (tablizer) - (1)
                                                                         Looks pretty specific. - (admin)
                                                     In Dejavu, one would write: - (FuManChu) - (8)
                                                         Re: In Dejavu, one would write: - (JimWeirich) - (2)
                                                             An earlier version was like that. - (FuManChu) - (1)
                                                                 Forgot: code links - (FuManChu)
                                                         ICLRPD - (drewk)
                                                         Why learn and/or create another query language? - (tablizer) - (3)
                                                             In case you missed it: - (FuManChu) - (2)
                                                                 only for the trivial - (tablizer) - (1)
                                                                     There are multiple ways of doing that... - (FuManChu)
                                             LCD *for my framework* - (FuManChu) - (103)
                                                 RDBMS > "data store" - (tablizer) - (102)
                                                     Re: RDBMS > "data store" - (admin) - (92)
                                                         still have not justified yet another tool/layers - (tablizer) - (91)
                                                             Re: still have not justified yet another tool/layers - (admin) - (90)
                                                                 before and after - (tablizer) - (89)
                                                                     Re: before and after - (admin) - (88)
                                                                         Then why have an OR-mapper middleman? -NT - (tablizer) - (87)
                                                                             Because: - (admin) - (86)
                                                                                 I forgot about query caching--a big part of my other app. -NT - (FuManChu)
                                                                                 Those are problems that OO introduces - (tablizer) - (84)
                                                                                     Re: Those are problems that OO introduces - (admin) - (83)
                                                                                         response - (tablizer) - (82)
                                                                                             Re: response 1 - (admin) - (3)
                                                                                                 Looks like a lot of beurOOcracy to me - (tablizer) - (2)
                                                                                                     Not claiming "victory" - (admin)
                                                                                                     Let's see your version, then. -NT - (pwhysall)
                                                                                             Re: response 2 - (admin) - (16)
                                                                                                 Re Re: response 2 - (tablizer) - (15)
                                                                                                     HQL is a superset of SQL - (admin) - (13)
                                                                                                         re: HQL is a superset of SQL - (tablizer) - (12)
                                                                                                             re: HQL is a superset of SQL - (admin) - (11)
                                                                                                                 Forced to use A to get B? Tsk tsk tsk. How MS of them. -NT - (tablizer) - (10)
                                                                                                                     You miss the point, anyway. - (admin) - (9)
                                                                                                                         I am not necessarily disagreeing with that here - (tablizer) - (8)
                                                                                                                             Re: I am not necessarily disagreeing with that here - (admin) - (7)
                                                                                                                                 not my burden of evidence - (tablizer) - (6)
                                                                                                                                     Wrong. - (admin) - (3)
                                                                                                                                         exist != good - (tablizer) - (2)
                                                                                                                                             Existence beats Non-Existence -NT - (ChrisR)
                                                                                                                                             I've already shown you. - (admin)
                                                                                                                                     Hm. So I can make any claim and force you to prove me wrong? - (FuManChu) - (1)
                                                                                                                                         Actually, what he said was: - (admin)
                                                                                                     Persistence vs. reporting - (admin)
                                                                                             Re: response 3 - (admin) - (55)
                                                                                                 Re Re: response 3 - (tablizer) - (54)
                                                                                                     Caching - (admin) - (2)
                                                                                                         Re: caching - (tablizer) - (1)
                                                                                                             Er, no it isn't. - (admin)
                                                                                                     Serial changes - (admin) - (50)
                                                                                                         "Bound" fields - (tablizer) - (49)
                                                                                                             No, no integration. - (admin) - (48)
                                                                                                                 re: No integration - (tablizer) - (47)
                                                                                                                     re: No integration - (admin) - (46)
                                                                                                                         So you want to see an Iwethey clone? - (tablizer) - (45)
                                                                                                                             I'd prefer you answer the points first. - (admin) - (44)
                                                                                                                                 We need code, not brochure-talk, to settle this - (tablizer) - (43)
                                                                                                                                     Re: We need code, not brochure-talk, to settle this - (admin) - (42)
                                                                                                                                         Is that part of iwethey? -NT - (tablizer) - (1)
                                                                                                                                             Yes. -NT - (admin)
                                                                                                                                         questions and comments - (tablizer) - (39)
                                                                                                                                             Reading comprehension? - (ben_tilly) - (2)
                                                                                                                                                 What is your complaint? - (tablizer) - (1)
                                                                                                                                                     Why not eliminate everything that is only a bonus? - (ben_tilly)
                                                                                                                                             Then don't bother. - (admin) - (16)
                                                                                                                                                 Fine. It is not "bloated". Just unknown. - (tablizer) - (15)
                                                                                                                                                     That's all I needed. - (admin) - (8)
                                                                                                                                                         Probably not telling you anything you don't already know... - (ChrisR) - (5)
                                                                                                                                                             I take it you mean... - (admin) - (1)
                                                                                                                                                                 Yep = That's what I meant - (ChrisR)
                                                                                                                                                             Re: Probably not telling you anything you don't already know - (JimWeirich) - (2)
                                                                                                                                                                 My memory is too taxed - (ChrisR)
                                                                                                                                                                 Memory Lane - (tablizer)
                                                                                                                                                         re: That's all I needed. - (tablizer) - (1)
                                                                                                                                                             re: That's all I needed. - (admin)
                                                                                                                                                     Caching - (admin)
                                                                                                                                                     Login checks and declarative processing - (admin) - (4)
                                                                                                                                                         re: Login checks and declarative processing - (tablizer) - (3)
                                                                                                                                                             re: Login checks and declarative processing - (admin) - (2)
                                                                                                                                                                 re re: Login checks and declarative processing - (tablizer) - (1)
                                                                                                                                                                     Re: Login checks and declarative processing (new thread) - (admin)
                                                                                                                                             I18N - (admin) - (18)
                                                                                                                                                 You are WRONG! - (tablizer) - (17)
                                                                                                                                                     My my, I touched a raw nerve, apparently. - (admin) - (16)
                                                                                                                                                         Grep is no substitute for clean, normalized data - (tablizer) - (15)
                                                                                                                                                             Re: Grep is no substitute for clean, normalized data - (admin) - (14)
                                                                                                                                                                 Depends on the scale - (tablizer) - (13)
                                                                                                                                                                     You've never used CVS either, have you? -NT - (FuManChu) - (3)
                                                                                                                                                                         No, only MS sourcesafe -NT - (tablizer) - (2)
                                                                                                                                                                             *shudder* - (admin) - (1)
                                                                                                                                                                                 Not my pickings -NT - (tablizer)
                                                                                                                                                                     Re: Depends on the scale - (admin) - (8)
                                                                                                                                                                         no no no - (tablizer) - (7)
                                                                                                                                                                             Re: no no no - (admin) - (6)
                                                                                                                                                                                 Doing my part to promote right shifting - (ChrisR) - (3)
                                                                                                                                                                                     "Oh goody, a new framework for xmas!" - (tablizer) - (1)
                                                                                                                                                                                         Re: "Oh goody, a new framework for xmas!" - (admin)
                                                                                                                                                                                     Internationalization (new thread) - (admin)
                                                                                                                                                                                 admin - (tablizer) - (1)
                                                                                                                                                                                     Resource files (new thread) - (admin)
                                                                                             Re: response 4 - (admin) - (3)
                                                                                                 Lock-in is lock-in - (tablizer) - (2)
                                                                                                     Query caching is a feature of JDBC - (admin) - (1)
                                                                                                         Yes - (tablizer)
                                                                                             Re: response 5 - (admin)
                                                     Most of those are problems, not solutions. - (FuManChu) - (8)
                                                         intense DBA and RDBMS bashing - (tablizer) - (7)
                                                             ..heh. Only because they deserve it. ;) - (FuManChu) - (6)
                                                                 re: Only because they deserve it. - (tablizer) - (5)
                                                                     I assume you already expect my response: - (FuManChu) - (4)
                                                                         I will agree that... - (tablizer) - (3)
                                                                             I've never claimed that _every_ O-R mapper is chicken soup - (FuManChu) - (2)
                                                                                 Most people can at least read Python within 5 minutes. -NT - (admin) - (1)
                                                                                     Whatever -NT - (tablizer)

7.8 on the Richter scale.
452 ms