[Qt-creator] Couple of questions about the design of Qt Creator

Eike Ziller Eike.Ziller at qt.io
Wed Oct 4 09:50:09 CEST 2017


> On 2. Oct 2017, at 09:29, Elvis Stansvik <elvstone at gmail.com> wrote:
> 
> 2017-09-11 10:00 GMT+02:00 Elvis Stansvik <elvstone at gmail.com>:
>> 2017-09-11 9:50 GMT+02:00 Eike Ziller <Eike.Ziller at qt.io>:
>>> 
>>>> On Sep 11, 2017, at 09:24, Elvis Stansvik <elvstone at gmail.com> wrote:
>>>> 
>>>> 2017-09-10 11:31 GMT+02:00 Elvis Stansvik <elvstone at gmail.com>:
>>>>> 2017-09-10 11:03 GMT+02:00 Elvis Stansvik <elvstone at gmail.com>:
>>>>>> Hi all,
>>>>>> 
>>>>>> In a quest to find inspiration for good Qt application architectures,
>>>>>> I've been looking at the plugin based one you're using in Qt Creator.
>>>>>> It strikes me as a really nice design.
>>>>>> 
>>>>>> I've been reading the available docs on it, and dug into the code a
>>>>>> bit. This may be a bit much to ask, but I was wondering if any of you
>>>>>> devs could answer a few questions that popped up? It would be much
>>>>>> appreciated!
>>>>>> 
>>>>>> It's really just two questions, about two different topics:
>>>>>> 
>>>>>> 1. The Invoker / invoke<...> Thingie:
>>>>>> 
>>>>>> You have ExtensionSystem::Invoker and the associated invoke<..>
>>>>>> helper, which are syntactic sugar for achieving "soft" extension
>>>>>> points. It seems it's not used that much (?). I grepped for
>>>>>> "Invoker|invoke<" in the code and could only find a few uses of it. I
>>>>>> also grepped for "invokeMethod" to see if the approach was being used
>>>>>> "manually" so to speak (without the sugar), and found a few more hits.
>>>>>> 
>>>>>> What was the motivation for adding this? I assume it's for cases where
>>>>>> you want a looser coupling between plugins (no linking, no shared
>>>>>> header), but can you give an example of when you really wanted that
>>>>>> looser coupling and why?
>>>>>> 
>>>>>> 2. The Plugin System in General:
>>>>>> 
>>>>>> Is there anything about the plugin system in its current form, or how
>>>>>> it is used, that you would do fundamentally different if you could do
>>>>>> it all over again? Any areas that you find messy/awkward, that need a
>>>>>> re-think/makeover? In short: What are the biggest warts in the code in
>>>>>> your opinion?
>>>>> 
>>>>> As soon as I hit send, I realized I have a third question:
>>>>> 
>>>>> 3. Communication Between Plugins:
>>>>> 
>>>>> There seems to be two main mechanisms through which plugins
>>>>> communicate: Either objects that implement shared interfaces are added
>>>>> to the plugin manager object pool and picked up by downstream or
>>>>> upstream plugins (in the top-down or bottom-up phase of plugin
>>>>> initialization, respectively), or a singleton instance is acquired and
>>>>> calls made on it.
>>>>> 
>>>>> Is the former approach used when dependants provide functionality to
>>>>> their dependees (which are unknown), and the latter approach used when
>>>>> dependees use their dependants (which are known)? Is that the deciding
>>>>> factor?
>>>> 
>>>> And finally, a couple of more down-to-earth questions:
>>>> 
>>>> 1. ICore, the class is concrete, so why the I in the name? Was it
>>>> abstract at one point?
>>> 
>>> Yes historically.
>>> 
>>>> How do you decide whether a class should get
>>>> the interface 'I' in its name?
>>> 
>>> It’s a mess ;)
>>> I suppose the trend goes to not prepend the ‘I’.
>> 
>> Ok, I figured there was a history :)
>> 
>>> 
>>>> The same with e.g. IContext, though
>>>> that one at least has a few virtuals and is used as a base class (but
>>>> no pure ones AFAICS, so still concrete).
>>> 
>>> Historically these classes where “pure” virtual (except for the QObject base).
>>> We moved to a more “configurable” approach then to avoid the need to create subclasses for every little thing, while keeping the option open in many cases.
>> 
>> Alright, this is what I suspected. Thanks for confirming.
>> 
>>> 
>>>> 2. The relatively liberal use of singleton classes. We all know that
>>>> is a debated subject, and I don't have an opinion either way. I'm just
>>>> interested in if you have some (spoken or unspoken) policy regarding
>>>> singletons in the project. Do you want to minimize the use of them, or
>>>> is it OK for newer code, or is it judged on a case-by-case basis? Have
>>>> you had any moments where you really wish you hadn't used singletons?
>>>> (e.g. I know it can sometimes hurt testability).
>>> 
>>> We always had a liberal amount of singletons in Qt Creator, and we even moved most of them to be classes with mostly static methods a while ago. There are no plans to move away from that. If you have a central hub for “managing” something, feel free to use a singleton/static methods.
> 
> Getting back to this semi-old thread with another question if that's OK:
> 
> Did the liberal use of singletons never get in the way of
> testability/mockability? Was there ever a moment when you though "o
> boy, I wish this thing didn't reach out to so many static things"
> while writing tests? If so, did you find a way to deal with that, or
> is it always just a compromise?

We use a whole lot of different testing methods which allow a different amount of integration between parts, and also developers usually only add tests where they think their usefulness outweigh the effort involved implementing them.
Also, different people in the project weigh the importance of tests differently, so you’ll probably get different answers from different developers.

- Auto tests: Standalone in tests/auto/... . This is where access to global state hurts most, and where UI is not great to test either. For auto tests you have to separate the individual functionality from “connecting everything” anyhow though. The global state often falls into that latter part, and with Qt’s signals and slots the separation can be done through that. E.g. for a new “advanced search” filter, you need to access global state to create a search result panel, adding search results there and reacting on user input through it. Testing the actual search, given a set of parameters is easy by simply separating that and using signals to report results. It is hard to test e.g. if repeating a search works correctly when the “search again” button is pressed, with this approach. Note that since basically all code of Qt Creator is in libraries, these can also be used in auto tests.

- Plugin tests: Can be triggered by running qtcreator -test MyPlugin. Plugins can have test methods which are then run _within_ Qt Creator after Qt Creator startup. This makes it possible to test functionality that integrates different parts / where global state is essential for the functionality. Its e.g. possible to load a project and throw your new advanced search filter on the project, and repeat a search. Or open a project, wait for parsing to finish, open a specific file, move the cursor to a location, trigger “follow symbol” and check the resulting location.

- Automated UI tests: Using Squish. Starts Qt Creator and simulates e.g. button presses by finding the buttons through the widget hierarchy, object names, etc. Used by a small number of QA dedicated people for automated tests in the style of “create new Qt Widget project, build & run, and check the state afterwards”.

Br, Eike

> I'm asking because in my current project, I'm trying to think about
> testability, using mocks where it makes sense, and one thing that
> really hurts testing in isolation is when code simply reaches out for
> something global (like a static instance/helper).
> 
> Elvis
> 
>> 
>> Okay. I also personally think the convenience of singletons outweighs
>> their drawbacks in many cases. Nice to see this liberating attitude.
>> 
>> Thanks for sharing Eike.
>> 
>> Elvis
>> 
>>> 
>>> Br, Eike
>>> 
>>> --
>>> Eike Ziller
>>> Principal Software Engineer
>>> 
>>> The Qt Company GmbH
>>> Rudower Chaussee 13
>>> D-12489 Berlin
>>> eike.ziller at qt.io
>>> http://qt.io
>>> Geschäftsführer: Mika Pälsi,
>>> Juha Varelius, Mika Harjuaho
>>> Sitz der Gesellschaft: Berlin, Registergericht: Amtsgericht Charlottenburg, HRB 144331 B



More information about the Qt-creator mailing list