Design of the engine : why abstract Ekiga::Foo and Ekiga::FooImpl matter

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Design of the engine : why abstract Ekiga::Foo and Ekiga::FooImpl matter

Julien PUYDT
Hi,


this mail is meant to explain why having two classes doesn't make the
code more complex just for the sake of it, but because it brings nice
features.


The fact that Ekiga::Foo is purely abstract means :

1. that anyone trying to write an instance of it, say Bar::Foo, will get
notified by the compiler if they forget to implement one of the methods,
or if they mispell one of them -- the compiler is helpful!

2. that anyone trying to write a very specific implementation is
completely free to do so, as the abstract class is, well, abstract ;

3. that anyone trying to write an implementation with no special needs
can just inherit Ekiga::FooImpl and be done!


So when writing new code, the presence of two classes doesn't get in the
way, and even gets the compiler to help : that is a bonus.


Now, now... we decide that Ekiga::Foo is too weak and add a method. This
immediately :

1. breaks Ekiga::FooImpl, which immediately gets fixed ; of course it
also breaks every class inheriting from Ekiga::FooImpl, but they all get
fixed at the same time -- and the fix can only be correct (more on that
later) ;

2. breaks every class inheriting from Ekiga::Foo, and the compiler says
so : the code won't compile as-is, someone will have to have a look at
all classes with very specific needs, and write correspondingly specific
implementations, so everything is correct.


And that's all : we made sure we either had all methods reimplemented or
none -- no in-between! So when modifying existing code, the presence of
the two classes ensures that the compiler will push every problem
explicitly under our eyes : there will be no silent break.


Compare with a situation where Ekiga::Foo has naive implementations of
everything directly in the base class:

1. Anyone writing an instance of Ekiga::Foo with an overriden
populate_memu (where the base had populate_menu) will have a hard time
knowing they made a typo : the compiler won't catch it. Silent break!

2. Anyone writing an instance of Ekiga::Foo may implement only two
thirds of the method, get something which won't run, but will gladly
compile. Silent break!

3. Anyone writing an instance with very specific needs will find the
variables used by the base class implementation in the way : if they
want to put some information in a 'tokens' variable the base class said
was a list of strings, but should now be a list of Bar::Token, will need
to name it my_tokens, but "tokens" will still take some room, and if
they forget a my_ somewhere, the compiler might not complain if they
don't use string/Bar::Token-specific api. Silent break!

4. You've been lucky : you only reimplemented populate_menu, and kept
the other base implementations because they fit. Someone modifies the
base implementation (added a method and made the default implementations
follow : all nice and clean!). Your code still compiles, but of course,
won't work. Silent break!


I think the purely abstract Ekiga::Foo and Ekiga::FooImpl is better : it
is more expensive, but you do get what you paid for.


Snark
_______________________________________________
ekiga-devel-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/ekiga-devel-list
Reply | Threaded
Open this post in threaded view
|

Re: Design of the engine : why abstract Ekiga::Foo and Ekiga::FooImpl matter

Eugen Dedu-2
On 14/01/15 08:43, Julien Puydt wrote:

> Hi,
>
>
> this mail is meant to explain why having two classes doesn't make the
> code more complex just for the sake of it, but because it brings nice
> features.
>
>
> The fact that Ekiga::Foo is purely abstract means :
>
> 1. that anyone trying to write an instance of it, say Bar::Foo, will get
> notified by the compiler if they forget to implement one of the methods,
> or if they mispell one of them -- the compiler is helpful!
>
> 2. that anyone trying to write a very specific implementation is
> completely free to do so, as the abstract class is, well, abstract ;
>
> 3. that anyone trying to write an implementation with no special needs
> can just inherit Ekiga::FooImpl and be done!
>
>
> So when writing new code, the presence of two classes doesn't get in the
> way, and even gets the compiler to help : that is a bonus.
>
>
> Now, now... we decide that Ekiga::Foo is too weak and add a method. This
> immediately :
>
> 1. breaks Ekiga::FooImpl, which immediately gets fixed ; of course it
> also breaks every class inheriting from Ekiga::FooImpl, but they all get
> fixed at the same time -- and the fix can only be correct (more on that
> later) ;
>
> 2. breaks every class inheriting from Ekiga::Foo, and the compiler says
> so : the code won't compile as-is, someone will have to have a look at
> all classes with very specific needs, and write correspondingly specific
> implementations, so everything is correct.
>
>
> And that's all : we made sure we either had all methods reimplemented or
> none -- no in-between! So when modifying existing code, the presence of
> the two classes ensures that the compiler will push every problem
> explicitly under our eyes : there will be no silent break.
>
>
> Compare with a situation where Ekiga::Foo has naive implementations of
> everything directly in the base class:
>
> 1. Anyone writing an instance of Ekiga::Foo with an overriden
> populate_memu (where the base had populate_menu) will have a hard time
> knowing they made a typo : the compiler won't catch it. Silent break!
>
> 2. Anyone writing an instance of Ekiga::Foo may implement only two
> thirds of the method, get something which won't run, but will gladly
> compile. Silent break!
>
> 3. Anyone writing an instance with very specific needs will find the
> variables used by the base class implementation in the way : if they
> want to put some information in a 'tokens' variable the base class said
> was a list of strings, but should now be a list of Bar::Token, will need
> to name it my_tokens, but "tokens" will still take some room, and if
> they forget a my_ somewhere, the compiler might not complain if they
> don't use string/Bar::Token-specific api. Silent break!
>
> 4. You've been lucky : you only reimplemented populate_menu, and kept
> the other base implementations because they fit. Someone modifies the
> base implementation (added a method and made the default implementations
> follow : all nice and clean!). Your code still compiles, but of course,
> won't work. Silent break!
>
>
> I think the purely abstract Ekiga::Foo and Ekiga::FooImpl is better : it
> is more expensive, but you do get what you paid for.

Hi Julien,

In case my opinion is useful:  I think you are right in theory and also
in a big program with many developers working 100% on it.  However, I
personnaly vote for pragmatism, for simple code ("simple is better!")
In our case, each time the code gets better from theory point of view,
gets harder to understand by someone wishing to be involved of.

Cheers!
--
Eugen
_______________________________________________
ekiga-devel-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/ekiga-devel-list
Reply | Threaded
Open this post in threaded view
|

Re: Design of the engine : why abstract Ekiga::Foo and Ekiga::FooImpl matter

Julien PUYDT
Hi,

Le 14/01/2015 10:32, Eugen Dedu a écrit :

> On 14/01/15 08:43, Julien Puydt wrote:
>> I think the purely abstract Ekiga::Foo and Ekiga::FooImpl is better : it
>> is more expensive, but you do get what you paid for.
>
> Hi Julien,
>
> In case my opinion is useful:  I think you are right in theory and also
> in a big program with many developers working 100% on it.  However, I
> personnaly vote for pragmatism, for simple code ("simple is better!") In
> our case, each time the code gets better from theory point of view, gets
> harder to understand by someone wishing to be involved of.
>
> Cheers!


Eh, my pragmatism says that it's the contrary : if we have few
developers with little spare time, it's vitally important to make sure
that code which compiles is code which works. Let the tools handle as
much as possible. Let's get out of the way so they can help. Will you
buy it if I call it "hardened design" ?


I call "very bad" a situation where a code modification somewhere will
compile perfectly, but silently and subtly break a few other places,
which will have to be found out by manual testing, hopefully before a
release by a tester... but more realistically after the release by a
user, tracked and fixed one by one with no help from the tools.


You can get the impression that things are easy and your productivity is
extremely high when you get something working in five minutes. But if
hours of debugging and fixing are hidden around the corner, I don't
think it's wise.


I have seen students write a fusion sort implementation which worked
wonderfully when given a list/array of length a power of two, and broke
in all other cases. But the code was so wonderfully short !


Let's not forget there's a fine line between simple and stupid!


Snark
_______________________________________________
ekiga-devel-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/ekiga-devel-list