You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@flex.apache.org by yishayw <yi...@hotmail.com> on 2016/08/08 08:22:31 UTC

[FlexJS] Interfaces, Pay as You Go, Performance

I thought I'd share a discussion we had on Matrices as it demonstrates some
problems in deciding how to do things 'the FlexJS way'.

We needed a TransformBead which uses a matrix as its model. We started out
by implementing the original AS3 matrix, which has members a, b, c, d, tx,
ty and a bunch of utility methods (copyColumnFrom, copyRowTo, rotate, etc.).
The utility methods seemed like clutter for most cases so in keeping with
PAYG we derived an interface that includes that mostly included access
methods to the members (get a, set a, get b, etc.) Now we had the option of
using more lightweight matrix when the utility methods were not necessary.
TransformBead relied on IMatrix implementors, which could be lightweight or
rich with convenience methods.

This sounds like 'the FlexJS way' but we ditched it for the following
considerations:

1) Method calls in JS are slower than direct access of properties. Forcing
models to implement methods rules out using a faster object.

2) The supposedly heavyweight model that is rich with convenience methods
doesn't actually result in heavy instances. The methods are all stored once
on the prototype and not duplicated per instance. So using the 'lightweight'
model doesn't really make the difference one might hope it would.

3) Removing the convenience methods from the main model opens up the
question of where they should be placed instead. An initial thought is to
implement them on different TransformBeads which require them (e.g.
RotateBead would have a matrixRotate() method), but that's not easily
reusable code. It seems to make sense to allow model manipulations to be
done on the model.

The main downside I see to the approach we took is that the application size
is unnecessarily bloated. If someone just needs a simple translation
transformation s/he will be confused and perhaps annoyed to see that the JS
code contains all sorts of methods that seem irrelevant. Also, we don't want
FlexJS mobile apps gaining a reputation of being device memory hoggers. 

So I'm still not decided on this. Any thoughts?



--
View this message in context: http://apache-flex-development.2333347.n4.nabble.com/FlexJS-Interfaces-Pay-as-You-Go-Performance-tp54380.html
Sent from the Apache Flex Development mailing list archive at Nabble.com.

Re: [FlexJS] Interfaces, Pay as You Go, Performance

Posted by Alex Harui <ah...@adobe.com>.

On 8/8/16, 9:50 AM, "yishayw" <yi...@hotmail.com> wrote:

>Alex Harui wrote
>> On 8/8/16, 6:23 AM, "Harbs" &lt;
>
>> harbs.lists@
>
>> &gt; wrote:
>> 
>>>> 2) The supposedly heavyweight model that is rich with convenience
>>>>methods
>>>> doesn't actually result in heavy instances. The methods are all stored
>>>>once
>>>> on the prototype and not duplicated per instance. So using the
>>>>'lightweight'
>>>> model doesn't really make the difference one might hope it would.
>> 
>> If extra methods are bringing in extra dependencies, then I would
>>consider
>> having a subclass with those extra methods/dependencies.  If the extra
>> dependencies are a few interfaces, then I would just bake them in.
>> 
>> My 2 cents,
>> -Alex
>
>To make sure I understand your point, I'll rephrase it: as long as we're
>not
>importing new classes to implement the convenience methods we should go
>ahead and add them. They should still implement some interface. Correct?

Well, it is always a trade-off.  If you add 100 APIs that only a few need,
then maybe you want to consider some other way of adding it later.  The
cool thing about JS is you can add methods to a class at runtime.

An interface is also optional.  For example, we don't have an IPoint
interface.  The Point class is just too simple to make it worth it.
Matrix probably doesn't need an interface either unless you think we'll
replace Matrix implementations instead of extending them with
plugins/beads.

>
>I hadn't considered compiler optimizations as a way to work around method
>call overhead. I think it makes for a convincing argument for freely using
>interfaces after all.

IMO, the whole point of compiler optimizations (and runtime optimizations)
is to find patterns in good code and make faster code.  Even an If
statement compiles to use the GoTos we aren't supposed to use in our code.
 Look up how Tail Call Optimizations are discussed as a way to optimize
delegate/proxy patterns like we use in the FlexJS wrapper components.
AIUI, the JS runtimes are investing lots of money in runtime optimization
like type inferencing, JIT and other really amazing things.  Some
researchers have shown that you can find some really complicated code path
and rewrite it as a single new inlined entity at runtime and reap huge
benefits.

As I see it, the entire industry, not just Apache FlexJS, is betting that
folks will need the overhead of structured code development to create
bigger and bigger apps and the runtimes/browsers are going to have to
support it.  So I am betting that we can write good code with interfaces
and the extra overhead of proxying between beads and we'll be better off
by doing that instead of writing hand-tuned JS.

So yes, IMO, more interfaces, but again, make sure they are useful and not
just an academic exercise.

Thanks,
-Alex


Re: [FlexJS] Interfaces, Pay as You Go, Performance

Posted by yishayw <yi...@hotmail.com>.
Alex Harui wrote
> On 8/8/16, 6:23 AM, "Harbs" &lt;

> harbs.lists@

> &gt; wrote:
> 
>>> 2) The supposedly heavyweight model that is rich with convenience
>>>methods
>>> doesn't actually result in heavy instances. The methods are all stored
>>>once
>>> on the prototype and not duplicated per instance. So using the
>>>'lightweight'
>>> model doesn't really make the difference one might hope it would.
> 
> If extra methods are bringing in extra dependencies, then I would consider
> having a subclass with those extra methods/dependencies.  If the extra
> dependencies are a few interfaces, then I would just bake them in.
> 
> My 2 cents,
> -Alex

To make sure I understand your point, I'll rephrase it: as long as we're not
importing new classes to implement the convenience methods we should go
ahead and add them. They should still implement some interface. Correct?

I hadn't considered compiler optimizations as a way to work around method
call overhead. I think it makes for a convincing argument for freely using
interfaces after all.




--
View this message in context: http://apache-flex-development.2333347.n4.nabble.com/FlexJS-Interfaces-Pay-as-You-Go-Performance-tp54380p54407.html
Sent from the Apache Flex Development mailing list archive at Nabble.com.

Re: [FlexJS] Interfaces, Pay as You Go, Performance

Posted by Alex Harui <ah...@adobe.com>.
On 8/8/16, 6:23 AM, "Harbs" <ha...@gmail.com> wrote:

>Th truth of the matter is that Matrix really had many more methods than
>really were needed for Matrix.
>
>I just trimmed down Matrix and removed all the methods that were not
>strictly Matrix related. This includes all Vector3D methods as well as
>gradient stuff.
>
>Here’s how I understand PAYG:
>
>1. Classes should be relatively small and deal with a specific piece of
>functionality.
>2. Additional functionality of components should be implemented as beads
>(separated into model and view when practical).
>3. Common code which is shared across multiple classes should be put in
>static utility classes to prevent code duplication and unnecessarily
>inflating classes for rarely used functionality.
>4. The utility classes should be small and have specific uses.

That's a pretty good list.  Additional functionality may go in subclasses
some times.  To be even more PAYG, utility classes would become utility
functions.

Sure, there is often a tradeoff between code size and
encapsulation/abstraction.  The way I think of it is that if you have
separation of concerns, the tool chain can someday optimize away some of
this overhead.  But if you entangle concrete classes, it is much harder or
impossible.

Maybe there is some issue with having servers and browsers use GZIP
compression over the wire, but to me, since that is possible and seems to
make sense, I tend to not worry so much about code size for FlexJS.
That's an example of the "tool chain" solving the right problem in the
right place.  Every time we add both an interface and a class instead of
just a class, we add a bit extra to the download size and initialization
time of the app, but I see that as an important tradeoff for future
cross-versioning issues, plus GCC hates circular dependencies, plus it
allows for other optimizations.

If GCC doesn't already do this, FalconJX, or some other post-processor
might be able to see that certain setters are just pass through (no change
events, just setting a backing variable) and reduce that to direct access
to the backing variable.  Optimizing compilers and runtimes have been
doing this for years, so this is the right place to worry about that.

Sure it would be great if FlexJS 1.0 was optimized in this fashion, but
before we manually optimize our code and reduce separation of concerns, we
should make sure those extra bytes or function calls are truly killing our
app.  But my philosophy is to use more interfaces in the framework code
and let other parts of the chain do optimization.

The other thing I factor in is what the JS side looks like.  If there is
no Matrix implementation, then you have more options as to how to
implement something.  Doing it the Flash way may not be the right way as
Flash doesn't use many interfaces.  So comments inline to Yishay's post
below.


>
>On Aug 8, 2016, at 11:22 AM, yishayw <yi...@hotmail.com> wrote:
>
>> I thought I'd share a discussion we had on Matrices as it demonstrates
>>some
>> problems in deciding how to do things 'the FlexJS way'.
>> 
>> We needed a TransformBead which uses a matrix as its model. We started
>>out
>> by implementing the original AS3 matrix, which has members a, b, c, d,
>>tx,
>> ty and a bunch of utility methods (copyColumnFrom, copyRowTo, rotate,
>>etc.).
>> The utility methods seemed like clutter for most cases so in keeping
>>with
>> PAYG we derived an interface that includes that mostly included access
>> methods to the members (get a, set a, get b, etc.) Now we had the
>>option of
>> using more lightweight matrix when the utility methods were not
>>necessary.
>> TransformBead relied on IMatrix implementors, which could be
>>lightweight or
>> rich with convenience methods.
>> 
>> This sounds like 'the FlexJS way' but we ditched it for the following
>> considerations:
>> 
>> 1) Method calls in JS are slower than direct access of properties.
>>Forcing
>> models to implement methods rules out using a faster object.

I still think the tools can optimize this some day, assuming change events
will not be needed.

>> 
>> 2) The supposedly heavyweight model that is rich with convenience
>>methods
>> doesn't actually result in heavy instances. The methods are all stored
>>once
>> on the prototype and not duplicated per instance. So using the
>>'lightweight'
>> model doesn't really make the difference one might hope it would.

If extra methods are bringing in extra dependencies, then I would consider
having a subclass with those extra methods/dependencies.  If the extra
dependencies are a few interfaces, then I would just bake them in.

My 2 cents,
-Alex


Re: [FlexJS] Interfaces, Pay as You Go, Performance

Posted by Harbs <ha...@gmail.com>.
Th truth of the matter is that Matrix really had many more methods than really were needed for Matrix.

I just trimmed down Matrix and removed all the methods that were not strictly Matrix related. This includes all Vector3D methods as well as gradient stuff.

Here’s how I understand PAYG:

1. Classes should be relatively small and deal with a specific piece of functionality.
2. Additional functionality of components should be implemented as beads (separated into model and view when practical).
3. Common code which is shared across multiple classes should be put in static utility classes to prevent code duplication and unnecessarily inflating classes for rarely used functionality.
4. The utility classes should be small and have specific uses.

I’m not sure what else goes into this list.

There’s actually  two kinds of “paying” in code. The first is in performance, and the second is in terms of code size. I think both should be considered.

In fact, there’s very often a trade-off in terms of code size as well. By adding additional classes to split up functionality, you can very often increase the total code size for a client who needs the sum total of the functionality. I think this is something which needs to be taken into account as well when breaking functionality into smaller pieces.


On Aug 8, 2016, at 11:22 AM, yishayw <yi...@hotmail.com> wrote:

> I thought I'd share a discussion we had on Matrices as it demonstrates some
> problems in deciding how to do things 'the FlexJS way'.
> 
> We needed a TransformBead which uses a matrix as its model. We started out
> by implementing the original AS3 matrix, which has members a, b, c, d, tx,
> ty and a bunch of utility methods (copyColumnFrom, copyRowTo, rotate, etc.).
> The utility methods seemed like clutter for most cases so in keeping with
> PAYG we derived an interface that includes that mostly included access
> methods to the members (get a, set a, get b, etc.) Now we had the option of
> using more lightweight matrix when the utility methods were not necessary.
> TransformBead relied on IMatrix implementors, which could be lightweight or
> rich with convenience methods.
> 
> This sounds like 'the FlexJS way' but we ditched it for the following
> considerations:
> 
> 1) Method calls in JS are slower than direct access of properties. Forcing
> models to implement methods rules out using a faster object.
> 
> 2) The supposedly heavyweight model that is rich with convenience methods
> doesn't actually result in heavy instances. The methods are all stored once
> on the prototype and not duplicated per instance. So using the 'lightweight'
> model doesn't really make the difference one might hope it would.
> 
> 3) Removing the convenience methods from the main model opens up the
> question of where they should be placed instead. An initial thought is to
> implement them on different TransformBeads which require them (e.g.
> RotateBead would have a matrixRotate() method), but that's not easily
> reusable code. It seems to make sense to allow model manipulations to be
> done on the model.
> 
> The main downside I see to the approach we took is that the application size
> is unnecessarily bloated. If someone just needs a simple translation
> transformation s/he will be confused and perhaps annoyed to see that the JS
> code contains all sorts of methods that seem irrelevant. Also, we don't want
> FlexJS mobile apps gaining a reputation of being device memory hoggers. 
> 
> So I'm still not decided on this. Any thoughts?
> 
> 
> 
> --
> View this message in context: http://apache-flex-development.2333347.n4.nabble.com/FlexJS-Interfaces-Pay-as-You-Go-Performance-tp54380.html
> Sent from the Apache Flex Development mailing list archive at Nabble.com.