Open 02JanDal opened 8 years ago
This would also make it a lot easier for possible new contributors to get started :+1:
There is no question that a major refactoring of some classes would be a good thing. But I guess you still underestimate the required effort (like probably both of us underestimated the effort of cleaning up after merging the map parts pull request).
The major challenges are
Indeed there is no point in refactoring without more automatic tests, and writing tests first is a good way to understand and document what is going on.
There are some lower hanging fruits to start with, such as
Well, the first steps, splitting and moving files, shouldn't alter any behaviour (unless there's code that depends on in which file it is placed, which I really, really don't hope there is), so that should be doable without tests. Once that's done we have smaller units (less classes per file at least), so writing tests should be somewhat easier at that point.
For writing tests; would including and using Catch be possible? It's assertions are way nicer to work with than those in QtTestLib, though it's not as integrated into Qt (most stuff still works though).
Also, to actually make the current tests useful for refactoring they should be checked through, autosave for instance takes almost 30s...
On me underestimating the work behind this: possible, but I don't think it should be done all at once. Small steps (split/move files, more tests, refactor code related to the tests, more tests, refactor code related to those tests, etc.).
So while #822 slowly moves forward, a list of stuff I want to do in the near future (in rough order):
The following would be roughly per directory, so would likely result in several branches/PRs in parallel
Q{Tree,List,Table}Widget
by real model/viewsAnother thing that might make sense eventually (not yet, I want to see it become a bit more mature) is replace the current 3rdparty dependency handling by conan, but that is to far into the future to make this list.
@dg0yt Any thoughts on the above?
Basically, I am reluctant to add more 3rd-party modules without clear benefit. And some changes really only make sense if there is more than one developer.
Give LaurentGomila/qt-android-cmake or the files included in ECM a try in an attempt to replace QMake, thus being able to clean up the build system.
I do not have much trouble with qmake. In the past, this was the most convenient way to try different "kits" in Qt Creator. OTOH I would appreciate Android being fully supported from CMake.
Do we currently support iOS (there are similar projects for it, but I don't own a device for testing that)?
No, and until yesterday I would have said it does not make much sense: Apple won't let GPL software into the app store, and thus it would be effectively impossible to distribute the app. However, there seems to be a new law suit challenging Apple's exclusive role in this game...
Add support for generating code coverage information to the build system using lcov/llvm-cov
I'm fine with that.
Set up Travis-CI (AppVeyor maybe in the future) and either codecov or coveralls for coverage upload (any preferences for which coverage service?)
openSUSE Build Service is my CI. Given the range of linux distributions covered, it catches a lot of issues. But its for packaging, it is not the kind of service Travis-CI is.
Include Catch for writing tests
What will we gain?
Add more unit tests (I'll say at least 50% coverage as an arbitrary goal, will likely need to be adjusted once we see how much coverage there already is)
That's a lot of work...
Split files, generally one class per file
Fine.
Other refactors (possibly separate PR from the above two)
Generally you will need a lot of PR, or every other work has to stop, or your big fat PR cannot be applied.
Replace Q{Tree,List,Table}Widget by real model/views
The focus should be on improving the core model first, not the UI.
Split large classes
... after having the unit tests
Another thing that might make sense eventually (not yet, I want to see it become a bit more mature) is replace the current 3rdparty dependency handling by conan, but that is to far into the future to make this list.
I looked at conan shortly. I'm not conviced I would make use of it. There is work in progress on bootstrapping the 3rd-party dependencies from a separate CMake superbuild project. Yes, just CMake, everything else can be pulled in. I need to solve a different problem: managing different trees of source code and binary results efficiently, including parallel builds, over a long period of time.
Basically, I am reluctant to add more 3rd-party modules without clear benefit. And some changes really only make sense if there is more than one developer.
We'll at least for a few things there's more than one now :wink:. Additionally changes that don't necessarily help a solo developer will likely help others who are interested in contributing but haven't yet.
Give LaurentGomila/qt-android-cmake or the files included in ECM a try in an attempt to replace QMake, thus being able to clean up the build system.
I do not have much trouble with qmake. In the past, this was the most convenient way to try different "kits" in Qt Creator. OTOH I would appreciate Android being fully supported from CMake.
I can fully see the benefit of continuing to use qmake. Maybe at least reduce the parts built by it to a single main.cpp
file and let the rest be a library? The reason I'd want to do this is because right now I don't really feel comfortable changing stuff in the build system for the risk of breaking the qmake part (there already was a smaller issue with that in the first PR), additionally it'd open up for putting some stuff into their own libraries (or at least own CMakeLists.txt
) in the future.
Set up Travis-CI (AppVeyor maybe in the future) and either codecov or coveralls for coverage upload (any preferences for which coverage service?)
openSUSE Build Service is my CI. Given the range of linux distributions covered, it catches a lot of issues. But its for packaging, it is not the kind of service Travis-CI is.
Yeah, the reason for Travis would be checking PRs, uploading of coverage etc. This might be possible to set up with OBS though, but that's not something I'd be able to help with.
Include Catch for writing tests
What will we gain?
A nicer way to write tests (slightly less code overhead since no class, WAY better assertions (you just write "normal" boolean expressions (a == b
) and it'll also print out the values of the variables). It's also distributed as a single header, so trivial to include.
Add more unit tests (I'll say at least 50% coverage as an arbitrary goal, will likely need to be adjusted once we see how much coverage there already is)
That's a lot of work...
As I said, arbitrary, and one directory at a time.
Other refactors (possibly separate PR from the above two)
Generally you will need a lot of PR, or every other work has to stop, or your big fat PR cannot be applied.
Ofc, but depends on how big the changes in each area are.
Replace Q{Tree,List,Table}Widget by real model/views
The focus should be on improving the core model first, not the UI.
The issue is that the code for the core is currently in the UI code. Doing this would move business logic to core, where it belongs.
Split large classes
... after having the unit tests
Yes, all changes that could result in changes of behaviour (both in code and to the user) will have at least a decent amount of unit test coverage.
Another thing that might make sense eventually (not yet, I want to see it become a bit more mature) is replace the current 3rdparty dependency handling by conan, but that is to far into the future to make this list.
I looked at conan shortly. I'm not conviced I would make use of it. There is work in progress on bootstrapping the 3rd-party dependencies from a separate CMake superbuild project. Yes, just CMake, everything else can be pulled in. I need to solve a different problem: managing different trees of source code and binary results efficiently, including parallel builds, over a long period of time.
I haven't quite understood what this superbuild thingy is for, nor why it is needed, but I'll try to keep my hands of this area for now.
Give LaurentGomila/qt-android-cmake or the files included in ECM a try in an attempt to replace QMake, thus being able to clean up the build system.
I do not have much trouble with qmake. In the past, this was the most convenient way to try different "kits" in Qt Creator. OTOH I would appreciate Android being fully supported from CMake.
I can fully see the benefit of continuing to use qmake. Maybe at least reduce the parts built by it to a single main.cpp file and let the rest be a library? The reason I'd want to do this is because right now I don't really feel comfortable changing stuff in the build system for the risk of breaking the qmake part (there already was a smaller issue with that in the first PR), additionally it'd open up for putting some stuff into their own libraries (or at least own CMakeLists.txt) in the future.
If we don't proceed too fast, the qmake changes can follow the CMake changes. It is a second-class citizen.
Set up Travis-CI (AppVeyor maybe in the future) and either codecov or coveralls for coverage upload (any preferences for which coverage service?)
openSUSE Build Service is my CI. Given the range of linux distributions covered, it catches a lot of issues. But its for packaging, it is not the kind of service Travis-CI is.
Yeah, the reason for Travis would be checking PRs, uploading of coverage etc. This might be possible to set up with OBS though, but that's not something I'd be able to help with.
Any reasonable integration with all these services will need Travis. I just won't touch it until I fully understand the implications, especially when it comes to granting privileges. (I looked into it a few times but wasn't satisfied. Cannot say if information was too poor or I was too tired.)
Include Catch for writing tests
What will we gain?
A nicer way to write tests (slightly less code overhead since no class, WAY better assertions (you just write "normal" boolean expressions (a == b) and it'll also print out the values of the variables). It's also distributed as a single header, so trivial to include.
I have looked at the web page, and I still asked the question. I do see some real benefits, but not the items you mention... Not sure how much you worked with our tests so far.
Regard Catch; well, I wouldn't rewrite the existing tests (at least not for now, way later if ever), but I've generally felt with Catch that you can focus more on writing tests and less on boilerplate and syntax.
How to add a new feature with minimal code in MapEditorController: b2d598e. PIMPLing MapEditorController is still needed in order to decouple feature units from map_editor_controller.h.
Quite some time since I last touched the source of this project...
Since these would be quite big changes I want to discuss them a bit before I even start to consider doing any of them:
I believe that Mapper is in dire need of some refactoring. All the below is done on latest master at the time of writing (c0713b5d343bfaf9ed2ab1c89dcf7ccff7a03fdf).
Files
src
folder contains 181 files... There are a lot of obvious possibilities for subfolders, just by looking at file names:tools
,gps
,symbol
,object
. There are also several dialogs and widgets that should probably move undergui/dialogs
andgui/widgets
here. Also severalfileformat_*
files that should move into the existingfileformats
, similar for util.Additionally there are many files that currently contain way more than a single class,
object.h
for example contains 2 large, 2 medium and a few smaller classes. These should probably also be split into separate files, which might change how the directory layout should be made.Classes
[ ] Next, there are many, many huge classes. You can argue about how big is to big for weeks, and everyone will have their own opinion. This blog post talks about the number 30 (30 lines per method, 30 methods per class, 30 classes per package/namespace etc.) and I believe that sounds quite sane, even though I think for a class that sounds quite high already, unless there is a lot of duplication through overloads, or implementations of well known abstract classes.
Lets look at some of the bigger classes in Mapper:
MapEditorController
: about a 170 methods. Yikes. While GUI classes can often become quite large with all the slots for different actions, this feels a bit extreme. 4 cores, 16 GB of RAM and still my IDE is just about usable when viewing this file.Object
: about 40-50 methods. Better, but a lot of potential for improvement.PathObject
: about 60 methodsMap
: I won't even count, above a 100 at least.The list goes on and on.
Object
hastags
,setTags
,getTag
,setTag
andremoveTag
. These could be moved into a separateTagContainer
class, leaving a singleTagContainer *tags() const
inObject
. Similar inMap
for templates, map parts, symbols and colours.There are also many classes that have their own
save
/load
functions, it might make sense to extract this functionality too.There are also several cases of classes that should probably be in part put into a
QAbstractItemModel
subclass. Most of the*Container
classes suggested above would make sense for this, or at least have a model class each that can be used to view them. BothTemplateListWidget
andColorWidget
contain aQTableWidget
that they need to keep updated, additionally to doing their actual job: handling the UI. The model handling part in these classes should be replaced byQTableView
with aQAbstractItemModel
subclass.Summary
Doing all this is a huge amount of work, especially splitting the classes. But I think it would be worth it. Doing this not only would improve the code base and improve build times, but also bring new features almost for free (adding map parts to the template widget as mentioned in #721 would take no more than maybe an hour or so once the template list is a model).
Once the mentioned changes are through there will likely be more patterns visible, yielding more things to refactor, but these big boulders need to get out of the way first.
I'd be happy to help out on whatever parts of this I can (will take me a while to get into the code base again), but first I want to know your thoughts on this.