Designing lower level classes.

G

Gunter Schelfhout

I'm starting to write a QT-program on Linux but I'm not very experienced
yet. (hang on, it will be on topic)
What is the best way to go to design the lower level classes?
Should I use the standard libraries as much as possible so I can reuse the
classes maybe in the future in non-GUI programs?
Or is it best to use as much of the QT-libraries from the beginning?
For example string <-> QString.
 
E

Erik Wikström

I'm starting to write a QT-program on Linux but I'm not very experienced
yet. (hang on, it will be on topic)
What is the best way to go to design the lower level classes?
Should I use the standard libraries as much as possible so I can reuse the
classes maybe in the future in non-GUI programs?
Or is it best to use as much of the QT-libraries from the beginning?
For example string <-> QString.

My advice, for any non-trivial application, is to divide the code into
(at least) two parts: one for the "business" logic and one for
interfacing with the application (be it a GUI, command line, or
something else). In the business logic part I would advice against using
more dependencies than necessary to keep the code as portable as
possible, but if a specific library does exactly what you need then use
it. You might also consider putting the lower layers in one or more
libraries which makes it even easier to change to GUI later on.
 
J

Juha Nieminen

Gunter said:
I'm starting to write a QT-program on Linux but I'm not very experienced
yet. (hang on, it will be on topic)
What is the best way to go to design the lower level classes?
Should I use the standard libraries as much as possible so I can reuse the
classes maybe in the future in non-GUI programs?
Or is it best to use as much of the QT-libraries from the beginning?
For example string <-> QString.

My personal experience on using GUI libraries is that you should,
obviously, separate what all the functionalities of the program which
you can into their own portable modules (this is rather obvious for the
simple reason that it's good OOD), but trying to abstract away the
non-standard GUI library completely from your program is usually more
trouble than it's worth.

I once tried this, and the results were less than satisfactory. My
intention was to make a clean abstraction of the underlying GUI library,
ie. hide everything in it inside its own module in a way that would
allow me to change the underlying GUI library easily to something else
(eg. from gtk to wxwidgets or to qt or to native Windows API or whatever).

While this sounds like a great idea in theory (and it still is), in
practice the whole system became awkward, limited and hard to maintain
and expand. At one point I simply noticed that I was basically
replicating the underlying GUI public interface in my own "abstract"
module. While I got something working, in the end I was not very
satisfied with the result. (And, rather ironically, the underlying GUI
library was never changed to anything else, so all that abstracting
basically went to waste.)

Sure, liberally using the GUI library everywhere in your code will tie
your code to that library in question, but whether that's better or
worse than the alternative is not clear at all. In some cases a clever
design could allow a clean abstraction between your code and the
library, but it's not easy.
 
G

Gunter Schelfhout

Juha Nieminen wrote:

[snip]
Sure, liberally using the GUI library everywhere in your code will tie
your code to that library in question, but whether that's better or
worse than the alternative is not clear at all. In some cases a clever
design could allow a clean abstraction between your code and the
library, but it's not easy.


I'm sure I'm not the only beginner facing this question and the most books
handle the technicalities of the language well but don't give any info like
this.
Probably this info will be in other more general progamming books I suppose?
I noticed the book 'Large scale programs with C++' or something from Addison
Wesley. I will look for a review. Maybe this is just the book I need for
questions like this.

Anyway, thanks a lot. It gives me something to think about.
 
S

Stefan Ram

Juha Nieminen said:
simple reason that it's good OOD), but trying to abstract away the
non-standard GUI library completely from your program is usually more

This usually will not work, because the GUI library often uses
callbacks or acts as a framework and by this it enforces a
specific structure of the high level code of the application,
and different GUI libraries indeed have different APIs,
because.

Separation still is possible, but just the other way around:
You abstract away every part of your program that is not
directly related to the user interface - but »abstract« now
is the wrong verb: You stash it away in a »model« and a
non-UI-related library to the maximum extend possible.

What is left over is a program that solely consists of UI
related parts (view and controller). This might be a text
console UI or a GUI. Now, this UI needs to be written for
every type of UI library used: For example, once for a console
library, once for GTK, once for WxWidgets, and so on. It is
the rest that cannot be abstract from the UI, because
everything else already has been stashed away in the model or
a non-UI-related library.

What is won by this approach is that the code for the model
and in the non-UI-related library does not have to be changed,
when writing the controller and view for a annother UI.
 
E

Erik Wikström

This usually will not work, because the GUI library often uses
callbacks or acts as a framework and by this it enforces a
specific structure of the high level code of the application,
and different GUI libraries indeed have different APIs,
because.

Separation still is possible, but just the other way around:
You abstract away every part of your program that is not
directly related to the user interface - but »abstract« now
is the wrong verb: You stash it away in a »model« and a
non-UI-related library to the maximum extend possible.

What is left over is a program that solely consists of UI
related parts (view and controller). This might be a text
console UI or a GUI. Now, this UI needs to be written for
every type of UI library used: For example, once for a console
library, once for GTK, once for WxWidgets, and so on. It is
the rest that cannot be abstract from the UI, because
everything else already has been stashed away in the model or
a non-UI-related library.

What is won by this approach is that the code for the model
and in the non-UI-related library does not have to be changed,
when writing the controller and view for a annother UI.

And if you ever want to incorporate the functionality of the application
in some other, bigger, application you just have to include the module/
link to the library. Even better, if you do create a separate library
and use a pure C interface, you can often use the module from other
programming languages.
 
G

Gunter Schelfhout

Stefan Ram wrote:

[snip]
What is won by this approach is that the code for the model
and in the non-UI-related library does not have to be changed,
when writing the controller and view for a annother UI.

Ok, since I am still in the design phase, it's probably better to keep
things separated as much as I can.
I'm glad I asked because on the IRC-channel of qt, people advised the
complete opposite.

Somebody who has good books of software design in his library which are
worth reading?
 
J

Juha Nieminen

Stefan said:
Separation still is possible, but just the other way around:
You abstract away every part of your program that is not
directly related to the user interface - but »abstract« now
is the wrong verb: You stash it away in a »model« and a
non-UI-related library to the maximum extend possible.

This is a good design, but possible (or, more precisely, feasible)
only if the core code of your program is not heavily dependent on the
GUI itself.

I have used this design myself many times. The typical situation is a
program which reads some input data, performs some lengthy and heavy
calculations/processing on it, and outputs the results to a file. The
core implementation (including I/O and the calculations) is easy to put
into its own separate module, and then it's easy to create a
command-line interface as well as a GUI application (using whichever
library) which uses this module in question. (Perhaps the thing which
needs the most careful design is how to pass the user-defined options
from the UI to the module.)

However, not all programs are like that. Many programs require, for
example, user input in real-time (such as mouse and keyboard events),
drawing things on screen, update some GUI elements (such as the value of
some spinbutton) and other such GUI-dependent functionalities. This is
where abstracting the core code from the GUI becomes laborious, if not
outright unfeasible.
 
S

Stefan Ram

Gunter Schelfhout said:
Ok, since I am still in the design phase, it's probably better to keep
things separated as much as I can.

It is not even required to keep it separated right from the
start.

You also can have some »dirty« code parts in the first version
where data processing and UI interface code is mixed and
refactor it later to get the separation. Not everyone is so
perfect that he can write it all separated from the start.

Between sessions of coding to extend the set of features,
there always should be sessions to improve the quality of the
code without adding new features. Nobody can write everything
in the best possible way the first time. But one will
eventually not be able to maintain the code anymore if one
never refactors it to improve separation of responsibilities.
 
G

Gunter Schelfhout

Stefan said:
It is not even required to keep it separated right from the
start.

You also can have some »dirty« code parts in the first version
where data processing and UI interface code is mixed and
refactor it later to get the separation. Not everyone is so
perfect that he can write it all separated from the start.

Between sessions of coding to extend the set of features,
there always should be sessions to improve the quality of the
code without adding new features. Nobody can write everything
in the best possible way the first time. But one will
eventually not be able to maintain the code anymore if one
never refactors it to improve separation of responsibilities.

I agree, but this is imho one of the decisions which are almost impossible
to switch back later on since a complete refacturing is then needed which
I'm trying to avoid.
So it's probably advisable to keep the the core classes as much as possible
independant of the GUI (and there libraries) and if nescessary, to provide
an extra layer to glue the core with the GUI.

I found out that between learning the technicalities and writing a program,
there is al lot more to discover. ;-)
 
E

Erik Wikström

It is not even required to keep it separated right from the
start.

You also can have some »dirty« code parts in the first version
where data processing and UI interface code is mixed and
refactor it later to get the separation. Not everyone is so
perfect that he can write it all separated from the start.

Between sessions of coding to extend the set of features,
there always should be sessions to improve the quality of the
code without adding new features. Nobody can write everything
in the best possible way the first time. But one will
eventually not be able to maintain the code anymore if one
never refactors it to improve separation of responsibilities.

I disagree, for the same reason. Nobody is perfect and once things work
it is all to easy to not refactor the code just to get a better design.
Write code with good separation from the beginning and then refactor the
interfaces between modules if needed. Also, this way you will keep the
"dirty" pieces of code well contained from other modules and you can
focus on one module at a time.

While I do agree that you should stop developing every once in a while
and take some time to clean up the code it might not always be possible
(while it is short-sighted many companies do not care about refactoring
until they absolutely have to). I believe in trying to get as good
design as possible from the beginning, since it (usually) keeps down the
decay-rate of the code. Of course, if you have good processes then it is
less of a problem.
 
E

Erik Wikström

This is a good design, but possible (or, more precisely, feasible)
only if the core code of your program is not heavily dependent on the
GUI itself.

I have used this design myself many times. The typical situation is a
program which reads some input data, performs some lengthy and heavy
calculations/processing on it, and outputs the results to a file. The
core implementation (including I/O and the calculations) is easy to put
into its own separate module, and then it's easy to create a
command-line interface as well as a GUI application (using whichever
library) which uses this module in question. (Perhaps the thing which
needs the most careful design is how to pass the user-defined options
from the UI to the module.)

However, not all programs are like that. Many programs require, for
example, user input in real-time (such as mouse and keyboard events),
drawing things on screen, update some GUI elements (such as the value of
some spinbutton) and other such GUI-dependent functionalities. This is
where abstracting the core code from the GUI becomes laborious, if not
outright unfeasible.

On the other hand, in these kinds of applications the GUI code is
usually a very large percentage of the whole application, if you ever
want to change GUI framework it will take a lot of work regardless of
how abstract your logic code is. When creating those kinds of
applications you really do not want to select the wrong framework,
because you'll gonna have to live with it for a long time.
 
S

Stefan Ram

Juha Nieminen said:
However, not all programs are like that. Many programs require, for
example, user input in real-time (such as mouse and keyboard events),
drawing things on screen, update some GUI elements (such as the value of
some spinbutton) and other such GUI-dependent functionalities. This is
where abstracting the core code from the GUI becomes laborious, if not
outright unfeasible.

In this case, the UI-dependent part of the program is large
and the UI-independent part of the program is small or missing.
Sometimes it happens to be this way, and then a port to another
GUI library will nearly be a complete rewrite. I do not see
any other solution for this case than to live (cope) with it.

A indication of such a type of program might be that it can
not be ported to some kinds of environment at all. For example,
when the definition of a program includes »drawing with the
mouse«, it will not be possible to port it to a keyboard
interface by its definition.
 
J

James Kanze

In this case, the UI-dependent part of the program is large
and the UI-independent part of the program is small or missing.
Sometimes it happens to be this way, and then a port to another
GUI library will nearly be a complete rewrite. I do not see
any other solution for this case than to live (cope) with it.
A indication of such a type of program might be that it can
not be ported to some kinds of environment at all. For example,
when the definition of a program includes »drawing with the
mouse«, it will not be possible to port it to a keyboard
interface by its definition.

This sounds like the old lightweight client vs. heavyweight
client dicotomy. Looking at the larger picture: at least in
business applications (but also in some of the process control
work I've done as well), there is a large body of "business
logic" (or application logic, if the application isn't
business), which can (and definitely should) be completely
separated from the GUI. In the lightweight client model, it is
so completely separated that it runs in a different program,
often on a different system. In which case, of course, the
client is almost pure GUI.

Regardless of where it is located, I would keep this business
logic completely separate from the GUI. In most cases, the GUI
itself will use some variant of MVC, in which the "model" serves
as a bridge between the GUI and the business logic (and doesn't
implement any of the business logic itself). (It's not all that
unreasonble to have the business logic run in a separate
process, even if it is on the same machine.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top