Avoid using Qt data types
-
wrote on 24 Jul 2020, 09:56 last edited by Jimmy Loyola
I always prefer to avoid using Qt data types (QString, QDateTime, etc.), or any other framework, inside my own business logic code to have less dependency to the framework. What do you think about this practice?
-
wrote on 24 Jul 2020, 17:29 last edited by
I'm happy to see this thread appear.
I am an advocate of reducing dependencies of all kinds whenever there is not a high cost to doing so.
I've worked on a large application that used a non-Qt GUI framework that later needed to be ported to Qt, and the porting process was way harder than it needed to be because no attention had been paid originally to minimizing the depth and breadth of that other framework's data types being used ALL OVER the codebase, not just where GUI was needed.
Another anecdote: The team working on Subsurface Dive Log has also given talks about their difficulties porting from GTK to Qt for the same reasons.
Clearly, in the above cases the teams wanted to move TOWARDS Qt, so this gives no "proof" that teams will later regret putting too much Qt dependence into all their libraries... but... what goes around comes around. "An ounce of prevention..." as they say.
@Chris-Kawa is right that "it depends." It always depends.
I'll share one more thought on this for now.
Leaving yourself the freedom and flexibility to port and reuse more of your code later on in the case of needing to break away from Qt dependence is not the only reason for trying to regulate and minimize which of your own modules use Qt.
Dividing your own code into discrete, de-coupled modules and being deliberate about which of them truly need Qt or not can be helpful in other ways. Here is one such situation:
Currently I am working on a system that involves an iOS device interacting on a LAN with several linux devices. The Linux devices are running Qt apps, but the iOS device is running a "pure UIKit" application. I have a lot of shared library code that I am using on both devices. That shared library code is written in stock C++ (no third-party dependencies), and I can compile it to a static ARM library for linking into the UIKit app, and compile it to a Linux "so" for linking into the Qt app.
-
I always prefer to avoid using Qt data types (QString, QDateTime, etc.), or any other framework, inside my own business logic code to have less dependency to the framework. What do you think about this practice?
@Jimmy-Loyola Nothing wrong with it if you can avoid Qt data types without too much hassle. Especially with recent C++ compilers there is less need for Qt own data types.
-
I think it's a risk assessment question i.e. how likely it is that you'll be replacing Qt with something else in the future.
If it's likely then keeping Qt code as a thin layer clearly separated is a good idea. The cost is then in conversions you have to do on the API boundary i.e. QString<->std::string, QVector<->std::vector etc. Qt also has a lot of stuff not readily available in std, so you miss out on some handy features. Transitioning back and forth can also incur performance cost, which, depending on a project, might not be acceptable.
If not then using Qt everywhere is kinda freeing and avoids a lot of trouble with conversions, registering custom types in meta system etc. A ton of helpers and implicit sharing in Qt's structures also can help to write simpler code. The cost in this case is of course high if you ever change your mind.
I've been through both paths and all I can say is - it depends.
-
I always prefer to avoid using Qt data types (QString, QDateTime, etc.), or any other framework, inside my own business logic code to have less dependency to the framework. What do you think about this practice?
wrote on 24 Jul 2020, 12:53 last edited by Jimmy Loyola@Chris Kawa In an MVC architecture I gladly use Qt data types in the View and in the Controller, they're awesome, but I think that the Model must be framework independent. Do you agree?
-
MVC is just a pattern. Choice of library for implementing it is orthogonal to that.
For example if you're implementing a Qt view you need a QAbstractItemModel for it and you can either implement it to directly operate on the data or as a layer on top of your Qtless model. Both approaches have pros and cons. This boils down to the same problem as before - how likely it is that you're going to need that model to be used for something other than Qt, so again - it depends.
-
MVC is just a pattern. Choice of library for implementing it is orthogonal to that.
For example if you're implementing a Qt view you need a QAbstractItemModel for it and you can either implement it to directly operate on the data or as a layer on top of your Qtless model. Both approaches have pros and cons. This boils down to the same problem as before - how likely it is that you're going to need that model to be used for something other than Qt, so again - it depends.
wrote on 24 Jul 2020, 13:08 last edited by Jimmy Loyola@Chris-Kawa If I apply SOLID principles in particular dependency inversion in all my model classes I don't have any Qt dependencies and my code is more flexible because it only depends on abstraction not about specific implementation. For basic types like string, vector I could use std data types.
-
@Chris-Kawa If I apply SOLID principles in particular dependency inversion in all my model classes I don't have any Qt dependencies and my code is more flexible because it only depends on abstraction not about specific implementation. For basic types like string, vector I could use std data types.
@Jimmy-Loyola said:
If I apply SOLID principles in particular dependency inversion in all my model classes I don't have any Qt dependencies and my code is more flexible
The question is always if you really need that flexibility for something.
By dry textbook definition it's fine, but in practice this usually means more classes, layers and abstractions, which lessens readability and sometimes performance. Sometimes you need it, sometimes you don't. I've seen my share of over-engineered solutions that made it nightmare to understand and modify because everything was forcefully made "flexible" while over 15 years none of that flexibility was ever used.
I've seen giant, extensible, flexible plugin system with one plugin that everyone hated to compile separately. I've seen macro based solution for generic multiplatform type system (before C++11 era) used for one platform, that every new employee hated and had trouble learning. I've seen multi layer, ultra flexible and extendable filtering models solution that after the person who wrote it left no one was able to modify without crashing the whole thing. Was thrown out and rewritten as one class that fit on a screen without any loss of functionality that was actually used. Did what it was supposed to and was almost never touched after that because there was no need to.
All I'm saying is patterns, rules and principles are all there to help you, but they are tools, not religion. Use when you need them, not because they are there and catch your eye.
We can talk about specific cases but I rarely see rules that fit every situation. Those rules and patterns are made by people in particular need and if your current needs align then great, by all means apply them. Just use your judgment before you use a tool. It's the ever present problem of everything looking like a nail when you're holding a hammer.
That being said I'm sticking to "it depends" :)
-
wrote on 24 Jul 2020, 17:29 last edited by
I'm happy to see this thread appear.
I am an advocate of reducing dependencies of all kinds whenever there is not a high cost to doing so.
I've worked on a large application that used a non-Qt GUI framework that later needed to be ported to Qt, and the porting process was way harder than it needed to be because no attention had been paid originally to minimizing the depth and breadth of that other framework's data types being used ALL OVER the codebase, not just where GUI was needed.
Another anecdote: The team working on Subsurface Dive Log has also given talks about their difficulties porting from GTK to Qt for the same reasons.
Clearly, in the above cases the teams wanted to move TOWARDS Qt, so this gives no "proof" that teams will later regret putting too much Qt dependence into all their libraries... but... what goes around comes around. "An ounce of prevention..." as they say.
@Chris-Kawa is right that "it depends." It always depends.
I'll share one more thought on this for now.
Leaving yourself the freedom and flexibility to port and reuse more of your code later on in the case of needing to break away from Qt dependence is not the only reason for trying to regulate and minimize which of your own modules use Qt.
Dividing your own code into discrete, de-coupled modules and being deliberate about which of them truly need Qt or not can be helpful in other ways. Here is one such situation:
Currently I am working on a system that involves an iOS device interacting on a LAN with several linux devices. The Linux devices are running Qt apps, but the iOS device is running a "pure UIKit" application. I have a lot of shared library code that I am using on both devices. That shared library code is written in stock C++ (no third-party dependencies), and I can compile it to a static ARM library for linking into the UIKit app, and compile it to a Linux "so" for linking into the Qt app.
-
@Jimmy-Loyola said:
If I apply SOLID principles in particular dependency inversion in all my model classes I don't have any Qt dependencies and my code is more flexible
The question is always if you really need that flexibility for something.
By dry textbook definition it's fine, but in practice this usually means more classes, layers and abstractions, which lessens readability and sometimes performance. Sometimes you need it, sometimes you don't. I've seen my share of over-engineered solutions that made it nightmare to understand and modify because everything was forcefully made "flexible" while over 15 years none of that flexibility was ever used.
I've seen giant, extensible, flexible plugin system with one plugin that everyone hated to compile separately. I've seen macro based solution for generic multiplatform type system (before C++11 era) used for one platform, that every new employee hated and had trouble learning. I've seen multi layer, ultra flexible and extendable filtering models solution that after the person who wrote it left no one was able to modify without crashing the whole thing. Was thrown out and rewritten as one class that fit on a screen without any loss of functionality that was actually used. Did what it was supposed to and was almost never touched after that because there was no need to.
All I'm saying is patterns, rules and principles are all there to help you, but they are tools, not religion. Use when you need them, not because they are there and catch your eye.
We can talk about specific cases but I rarely see rules that fit every situation. Those rules and patterns are made by people in particular need and if your current needs align then great, by all means apply them. Just use your judgment before you use a tool. It's the ever present problem of everything looking like a nail when you're holding a hammer.
That being said I'm sticking to "it depends" :)
wrote on 25 Jul 2020, 12:38 last edited by Jimmy Loyola@Chris-Kawa Thank you! If I already know from the beginning that one day I could change framework I wouldn't even be asking this question. The point is that I don't know if this can happen so I want to understand how to prepare myself for this. One day the core of my codebase could be used in different contexts with different technologies, with different graphic libraries, making it independent to Qt does not seem to me a big effort because std has excellent helpers and data structures. Regarding code flexibility, if it is well written there are no valid contraindications, from your experience I can understand that there has been a failed attempt to apply object-oriented programming techniques, this often happens due to the lack of time to find the most suitable design. Flexible "well written" code does not bring problems, that's not its goal. Implementing repository pattern you could have more classes, layers and abstractions but it semplify a lot automatic test writing.
-
wrote on 27 Jul 2020, 08:00 last edited by
"It depends!" is totally the right answer here. We are almost done porting a programm from wxWidgets to Qt. It took us a lot longer than expected (about twice as long). The wx-classes were all over the place and have now been replaced by their Qt equivalents. It would be really hard to automate that on the computer, but in the end this part is only a visual search&replace. Replacing these classes was actually comparatively fast and didn't take too much time. Though, this time could be saved if it did not have depended on wx in the first place. Still, I would nevertheless prefer to not have it any other way if I had to do it again. At least for our software I would vote to have the dependencies to Qt.
One thing I'd like to mention is that Qt is a very powerful framework. I don't know GTK, but in general I would assume that Qt is the most powerful/comprehensive portable C++ framework out there. So, it might be easy(-ish) to port from other frameworks to Qt, but I expect it to be much harder to port from Qt to another framework. This is a point specific to Qt you should consider.
If performance is of some concern in your application it might also make sense to use Qt's classes everywhere. For QString and QVector, etc. you get implicit sharing guaranteed. If you rely on STL classes implementation might change when switching platforms. I would expect a more consistent experience when only using Qt classes. Also, string manipulation is a lot easier in Qt than with STL classes. Again, this might make it harder in the future to port away from Qt.
I do avoid Qt in certain areas. In our company Qt is only used for the GUI applications. However, the actual simulation software runs on the command line. I have no reason to introduce Qt to our existing command line software. And personally, I would never write command line applications with Qt. Having the extra dependency is not worth it (too much trouble deploying these on clients' computers). This also means that every module which is shared between the GUI application and the command line applications does not include any Qt.
-
"It depends!" is totally the right answer here. We are almost done porting a programm from wxWidgets to Qt. It took us a lot longer than expected (about twice as long). The wx-classes were all over the place and have now been replaced by their Qt equivalents. It would be really hard to automate that on the computer, but in the end this part is only a visual search&replace. Replacing these classes was actually comparatively fast and didn't take too much time. Though, this time could be saved if it did not have depended on wx in the first place. Still, I would nevertheless prefer to not have it any other way if I had to do it again. At least for our software I would vote to have the dependencies to Qt.
One thing I'd like to mention is that Qt is a very powerful framework. I don't know GTK, but in general I would assume that Qt is the most powerful/comprehensive portable C++ framework out there. So, it might be easy(-ish) to port from other frameworks to Qt, but I expect it to be much harder to port from Qt to another framework. This is a point specific to Qt you should consider.
If performance is of some concern in your application it might also make sense to use Qt's classes everywhere. For QString and QVector, etc. you get implicit sharing guaranteed. If you rely on STL classes implementation might change when switching platforms. I would expect a more consistent experience when only using Qt classes. Also, string manipulation is a lot easier in Qt than with STL classes. Again, this might make it harder in the future to port away from Qt.
I do avoid Qt in certain areas. In our company Qt is only used for the GUI applications. However, the actual simulation software runs on the command line. I have no reason to introduce Qt to our existing command line software. And personally, I would never write command line applications with Qt. Having the extra dependency is not worth it (too much trouble deploying these on clients' computers). This also means that every module which is shared between the GUI application and the command line applications does not include any Qt.
wrote on 27 Jul 2020, 09:42 last edited by Jimmy Loyola@SimonSchroeder That's the point, che core code of your application must run on GUI and Console application without any complication because it should work only on the data model defined by your business logic and doesn't have to depend to any specific graphic library. It always depends, for everything, even bad practises and bad code are perfectly explainable and acceptable in some cases, but in this case we don't to think in this way. Qt is perfect to create GUI but the code must be easily tested in a console application.
1/11