On Tue, Apr 11, 2017 at 6:15 PM, Cedric BAIL <cedric.b...@free.fr> wrote:
> On Mon, Apr 10, 2017 at 7:46 PM, Gustavo Sverzut Barbieri
> <barbi...@gmail.com> wrote:
>> On Mon, Apr 10, 2017 at 7:12 PM, Cedric BAIL <cedric.b...@free.fr> wrote:
>>> Finally something that we are not addressing yet, but would I think
>>> make sense, is some way to describe simple layout (Like Android XML
>>> file or Microsoft XAML). With Eo property it becomes quite easy to
>>> automatically generate code for this.
>>
>> We're incurring in the same error as we did for EDC, thinking much of
>> our side instead of users... EDC started as something for designers
>> but then we never provided WYSIWYG and it sucked... the primitives are
>> all there, but unusable for the naive or designers.
>>
>> the only way to describe this is to create a WYSIWYG first, then come
>> with some format to store it... But do that as the *USER* point of
>> view, not from EFL development PoV. Ignore our terms, ignore our
>> limitations, try to make design use cases and then we see how to
>> implement that with our tech, adding features and removing limitations
>> as needed.
>
> That's where I have a different opinion. Developers are bad with
> WYSIWYG interface.

This is not true, what is true is that most WYSIWYG sucks and for
repetitive tasks they are often hard to automate, which leads to the
effort to do it manually "worth the cost", since you can later
automate it.

Simple counter example to your argument is: who edits images using
code only? while convert and programming can get you the same results,
most often than not we're using Gimp or Inkscape to edit these, as
it's just cumbersome to do it manually -- the balance on non graphical
tools is only good for simple operations like "scale", where you can't
get much wrong.


> Designers are the users of that potential WYSIWYG
> interface. Problem is that in the population we are trying to address,
> a large portion of them are developers without a sidekick designer.
> They are the one who want to be able to do simple UI "assemblage" from
> a file.

Okay, however if we're creating yet-another-Glade, we'll fail...
interfaces moved on from that pack-a-widget...


> EDC is way to complicated and powerful for what they want. We
> actually do not have anything to address the needs of this people.
> This is what I am talking above.

Okay, if you consider the LANGUAGE,  but the TOOL can be simpler or
more complex. Like full blown editor or a simple "pack-a-widget". If
possible allow to be the same tool, only different exposition, so
whenever needed one can migrate from pack-a-widget to
flash-like-rich-UI.


> [...]
>
>>> We have been iterating over a MVC design for more than a year now. I
>>> think we are nearing a design that start to look good. The funny part
>>> is when I was trying to find some presentation to explain people about
>>> MVC and the difference with what we were doing, I stumble on Microsoft
>>> MVVM design pattern which is pretty close to the design we have
>>> selected. So we will rename the work we have done from ProxyModel to
>>> ViewModel to use the same naming convention as everyone else.
>>>
>>> The main difference between MVC and MVVM is that it allow the
>>> definition of a clean interface between View and Model. There isn't
>>> really a ProxyModel or ViewModel interface, as they really are just a
>>> Model that get data from another Model and interpret them into what
>>> the View will actually display. This means you can easily reuse Model
>>> and that you can test your Proxy/ViewModel without connecting it to an
>>> actual View.
>>>
>>> And last very nice benefit, I think, is that you are defining a
>>> "connection" for each parameter of your widget. So to connect a View
>>> with a Model, you are only setting the model and indicating which
>>> property to fetch on the model. No need to deal with callback in many
>>> case ! For an example (which is broken at the moment) of the idea you
>>> can look at layout_model_connect.c in efl elementary example.
>>>
>>> The most complex work will now be in writing this Proxy or View Model.
>>> This is something we have to work on to make it easier.
>>
>> I've talked to you and felipe at IRC, I still think that the current
>> Model is trying to address too much of "performance and async" at the
>> level that it will suck for developers.
>>
>> to address the correct goal of "never block", what the current
>> implementation does is make all property-get async, resulting in a
>> promise... callback, etc. Whenever you need a simple:
>>
>>   if (model.a + model.b < model.c) do_bla(model);
>>
>> then you're screwed... you need to store these elsewhere, wait on 3
>> callbacks, then execute what you want. Okay, helpers to accumulate and
>> wait on all futures... then dispatch an array of values will be there,
>> but still.
>>
>> caching is also left to outside. But to cache properly you need to
>> know your information, access pattern, load coast, evict cost... Okay,
>> applications may know better which information they are going to use,
>> but they can hint that to model if needed (we could add a way to
>> declare "hot properties").
>>
>> My suggestion is that we benefit from "models are live entities and
>> always change", thus the users *MUST* monitor the changed events...
>> and make all property getters/setters synchronous. However you may
>> call a property get and receive a dummy value, which will trigger the
>> fetch of real values, then emit "changed", which will likely trigger
>> the code path again and that one will receive the actual values.
>
> My main concern with this proposition is that it is very very easy to
> write blocking code

As said at IRC, this is an issue in every case. We can always write a
recommendation, provide good core Models (FS, DB...) and hope people
will follow.

It's not creating a Promise and returning its Future that will get you
async, in reality it's not helping anything, because if the user
happens to call a blocking-and-slow API from the main thread, the
result will be the same OR WORSE. Example:

   I have My_Slow_Call() that is synchronous, then I create an
efl_loop_job to fulfill the promise, from that job callback I call
My_Slow_Call(). Result? stalled the whole UI. Blame the user? Excuse:
"but it did it asynchronously!"... point him to mistake "See, it's
being called here, async --> from main loop, it must be
ecore_main_loop_begin's fault!"

It's even harder to debug, you can't know who triggered that. OTOH if
people create a horrible "property_get()", you can easily track by the
call stack, gprof will point it, etc.

NOTE: if you make our own slow APIs "sync-unfriendly", then there is
no way to do these mistakes if you stick within EFL. All the slow
apis, like list-a-dir and the likes being async would push the users
to cooperate the the async behavior... because it would be EASIER.

It doesn't solve the foreign libraries, which are more likely to cause
problems in both cases.


> and it makes also the code of the model more complex in the sense
> that you have to remember which request you are currently answering
> and where your dummy values are.

Not really.  You don't need to remember which requests you're
answering, you only trigger a "realize" to fetch real data and then
emit "changed" event.

At most, if you're realizing each property individually, you'd have
one per property, like a handle that is responsible to execute that
(ie: Ecore_Thread, some Object such as Efl.Loop_Timer/Efl.Loop_Fd...).
But you'd need that anyway in both cases (you can't simply ignore
those). Code would look like:

    if (pd->resolving || pd->resolved)
       return;
    pd->resolving = resolve(o);

where "resolved" is usually inferred from the actual value, or a boolean flag...


> The reason we push for a single API to fetch property is because we
> want to simplify the logic by having just one pattern to be implemented
> in model. Ideally this would mean that the monitoring is to be done solely
> by the root model and the leaf.

Actually I talked to Felipe and I recall the consensus was that this
approach resulted in LESS API to be exposed and simplified the
results, at some point Felipe went further to say that we should have
NO "get(proname)", rather just the "changed" event, which would
provide ALL properties... then you're forced to listen for "changed"
and react properly. It's not that intuitive, but would force correct
behavior. We'd have to make a good "info" in the event, so we can
provide all properties and a way to tell which actually changed (my
initial guess is that "changed" would provide the property names that
changed, then you'd get() what interests you).

Also, with an explicit get(propname) you can know what's interesting
to load/fetch... eventually for a File Model you only need its name,
so no need to stat(). For DB you can only fetch some columns (ie: for
each unrealized property-column, append to a list "to realize" and
then create a single thread/job/idler to do it).


> I understand why you want to go with your model. It will by design
> force us to implement a cache/dummy in each model, but this doesn't
> mean you can't have a cache with promise/future as the method to
> fetch.

For sure, but then you're be hammering the mempool+main loop to
provide stuff you already know.


> It will also provide an information to the View right away
> (Even if not valid, it will have a default value). The idea in our
> case is to set the default value on the View and maybe also the value
> to be set in case of error (as an helper).

You can have both, like return that the property is not available
(Eina_Error) while still setting the value, or simply create a
specific Eina_Value that means "no value yet", after you fetch the
value you check its type to know whenever it's real or you should wait
(much like stat.d_type == DT_UNKNOWN).

> This way if the real value
> take some times to be fetch, it won't require multiple fetch of the
> same value. The main difference is that we force people to always go
> with an async model, this reduce the likeliness that someone will come
> with some code that will stall the UI which is a real concern.

as per above case, it's not the definitive solution :-/


>> example: FS model. walking a directory and generating children models
>> will give you the filename and MAYBE the d_type (it may be
>> DT_UNKNOWN). You know the rest of the model is sizeof(struct stat),
>> which makes your Eo private data very small. Once a property get that
>> needs 'stat()', then you return dummy values but trigger an
>> async/thread/eio stat... that will give you ALL the fields (mode, uid,
>> gid, size...). Unless object changes (ie: inotify), then no extra
>> async call, promise/future are needed.
>>
>> compare this to the implementation where N calls to get("size"),
>> get("mode"), get("uid"), get("gid") will result in N*4 promises/future
>> pairs, N*4 callbacks...
>
> We have been talking about providing an API for doing grouped fetch,
> but pushed that to later as we don't think it will really impact
> performance that much. We only fetch property that are actually
> visible and used by a View. How many property will you fetch on one
> screen ? And when it does become a problem, we can address that by
> sending back an array, structure, hash, whatever for a group fetch. I
> don't think it is an inherent problem.

see, you'd add more API to solve something that would not exist in the
one I'm suggesting.

In most systems, models are created by more skilled people since they
exist in less number or needs, while views are in larger number, so
less skilled people.

We should rather put effort to provide a good set of models that are
very good and create helpers for people to derive their own, this is
particularly true for DataBases, this is why people use ORM so much,
you only give them few DB details and it will execute SQL commands,
cache results, etc. I'd do the same for DBus, XMLRPC and JSON-RPC...
which would cover most of the usages, people only need to specify
which properties, that's it.


>> DB can be done like that as well. My experience with Canola running
>> Python on a Maemo 770 (64mb ram, armv5) required us to do exactly
>> that. DB access resulted in shallow objects, that were populated as
>> needed. In our case, when a 10,000 song DB was queried, we would only
>> call 'SELECT COUNT(*) FROM TABLE' and say we had 10,000 song without
>> creating any actual children. Then when an index/slice/range was
>> asked, we'd optimize block/group load ('LIMIT = X', X being multiple
>> of 10, 100 or whatever). and only the important/cheap information,
>> like Music title. Whenever the user asked for cover, length, artist...
>> these would "pagefault" and load the values with individual 'SELECT',
>> populating the model as needed.
>
> We do have exactly that in our current model. We would set the count
> and would fetch children for a given range too. There is indeed no
> point into loading all of them and it critical to not load what has no
> chance to be display by any View.
>
>> This is also great approach when you have in-memory info, as you never
>> generate async calls... say you're exposing Eet-decoded object in
>> Efl_Model... what's the benefit of generating many promise/future?
>> It's all in there, all memory is easily accessible. That's also the
>> case for things like JSON, where you can tokenize and keep pointers to
>> in-memory buffers, then it's a memcpy and some eventual decode (like
>> parse the int/float... unescape strings...)
>
> The point is to push people to write asynchronous code. EFL is able to
> keep up with a UI at 60fps on a lot of hardware, but more often than
> not we are pointed to code that perform poorly, because they didn't
> implement it in an asynchronous way. Sure there is an overhead with
> promise/future, but there is a overhead also with MVVM. What is the
> benefit of using a data model in the case you describe ? Well,
> reusability, clearer code construction, easier to extend... I think
> this apply to make the fetching of property an asynchronous call to.

You can use model to test, like cmdline test utility... you can use
properties of those models to create custom/calculated information, as
not always what you receive is what you're going to show...

not all UI will be "autofilled" by our code, then for those who will
write custom UI, the cost of getting it right will grow a lot... and
of course, there is no magic, our own code is growing in complexity as
well.

-- 
Gustavo Sverzut Barbieri
--------------------------------------
Mobile: +55 (16) 99354-9890

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
enlightenment-devel mailing list
enlightenment-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/enlightenment-devel

Reply via email to