couchdb-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Alexander Shorin <kxe...@gmail.com>
Subject Re: [jira] [Commented] (COUCHDB-1397) Function expressions, evals in SpiderMonkey
Date Mon, 06 Feb 2012 02:39:32 GMT
Hi, Jason!

I'd like to share your disagreement about global functions (emit, log,
send etc.) if only I haven't rewritten query server line by line.
Actually, they are start to be global at function source code
compilation[1][2], so nobody stops you to change their context. But
you may notice, that view functions shares some invalid functions for
their context. e.g.
function(doc){
  emit(doc.foo, 1);
  while(row=getRow()){
    // ooops...(:
  }
}
So you just wanted to have some control on function compilation
context? I suppose Couch[3] object could help you to define custom
context, overload default emit, log and other functions. May be using
Javascript query server internals a little unhandy, but some wrappers
could make it sweet(:

Hiding current "global" function to some object or module means
breaking all design function. Idea with requiring them (I mean your
`var couch=require("couch");`) looks nice from code design style, but
as lazy developer this looks like overhead that I should write because
without it my functions couldn't work at all! Not so relaxed as it
currently does.

About testing couchapps.
IMHO, there is no problem(: Function context could be easily
overloaded, but I dont think that unittests are good idea for them.

For testing Python couchapps I'd prefer black box testing[4] instead
of unit one because of some simple reasons.
Main profit of black box testing in this case that it works as is, I
dont have to care about mocking global function, emulating CommonJS,
mime type guessing routines etc. they are just have done well and
works well. If I need test against some CouchDB version, I just
specify target version and I'm aware about some specific behavior of
them - unittests couldn't get me such information.

For example, I could easily mock require function and make CommonJS
modules works for view functions, but these functions wouldn't
actually work in CouchDB before 1.1 version - this feature just was
not implement(:

Also, it's a simple task to test views, but much more pain you will
get by testing show and list functions[5], especially for second one
because they working in bi-direction way: reading input stream while
output is not finished, collecting chunks stack and flushing them back
for each getRow round...hellish function for well unit testing(:

So, resuming wall of text above:
0. Design function context could be customized;
1. Wrapping current pseudo global functions to CommonJS module or some
context object breaking a lot of code and makes it useless without
additional work;
2. Query server internals could help you in testing your couchapps;
3. Couchapps unittests are too synthetic and couldn't revive all
possible problems. Should you do same work twice?

[1] https://github.com/apache/couchdb/blob/master/share/server/util.js#L64
// compilation
[2] https://github.com/apache/couchdb/blob/master/share/server/loop.js#L16
// namespace definition
[3] https://github.com/apache/couchdb/blob/master/share/server/util.js#L59
// Couch object
[4] https://code.google.com/r/kxepal-couchdb-python-featured/source/browse/couchdb/tests/server/qs.py?name=viewserver#241
// very simple and synthetic, but I'm awaiting for Dirkjan review of
current state before adding more features to simplify testing(:
[5] https://code.google.com/r/kxepal-couchdb-python-featured/source/browse/couchdb/tests/server/render.py?name=viewserver#235

--
,,,^..^,,,



On Mon, Feb 6, 2012 at 5:04 AM, Jason Smith <jhs@iriscouch.com> wrote:
> Hi, Marcello and Alexander. Perhaps we can move this to the mailing
> list and off the JIRA ticket?
>
> On Sun, Feb 5, 2012 at 11:21 PM, Marcello Nuccio (Commented) (JIRA)
> <jira@apache.org> wrote:
>>
>>    [ https://issues.apache.org/jira/browse/COUCHDB-1397?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13200798#comment-13200798
]
>>
>> Marcello Nuccio commented on COUCHDB-1397:
>> ------------------------------------------
>>
>> @Alexander,
>> this isn't as off-topic as it seems at first, because software design is heavily
influenced by ease of testability.
>
> Firstly, I'm unsure if you noticed but I made a typo which gave my
> statement the opposite meaning.
>
> I agree that emit(), log(), etc. should NOT be global.
>
> However, I disagree that they should be passed to map(), simply
> because it burdens the programmer. Plus, if we add new functions in
> the future, it would change the call signature of map functions. On
> the other hand, we get the same benefit by passing the functions but
> using a closure to put them in scope of map(), reduce(), etc.
>
> The map function might be built like so (the example is imperfect but
> I'm aiming for clarity for now):
>
> Given: ddoc.views.people.map = "module.exports = function(doc) {
> emit(doc.name, 1) }"
>
> var make_map = Function("require, module, exports, emit, log",
> ddoc.views.people.map)
> var map = make_map(require, module, exports, emit, log)
>
> map({name:"Bob"}) // Runs emit("Bob", 1)
>
> ## Unit testing
>
> It's imperfect for unit testing; however I think a hypothetical NPM
> package would be fine. It could convert the ddoc functions to
> JavaScript functions in a similar fashion. (Below is the first API
> that popped into my head, no doubt we could make better.)
>
> var assert = require('assert')
>  , couch = require('mock-couchdb')
>
> var ddoc = couch.load_ddoc({views: {people: {map: "function(doc) {
> emit(doc.name, 1) }"}}})
>
> var emitted
> ddoc.on('emit', function(key, val) { emitted = key })
> ddoc.views.people.map({name:"Bob"})
> assert.equal(emitted, "Bob")
>
> --
> Iris Couch

Mime
View raw message