April 6, 2021

An Experiment with QSqlTableModel and SQLite

  —Trying out Composite Primary Keys with Qt's QSqlTableModel.

I found the interaction between Qt’s QSqlTableModel and composite primary keys difficult to understand. Those difficulties involved recurrent “No Fields to update” messages from QSqlError::lastError() when trying to insert. This post captures a small series of experiments to better understand the behavior. I started with a working example from the Qt Forum.

The code for this post is in a Git repository.

CREATE TABLE preferences(
    x TEXT NOT NULL,
    y TEXT NOT NULL,
    PRIMARY KEY(x, y)
    WITHOUT ROWID;

I’m using SQLite (3.28.0 2019-04-16 19:49:53 884b4b7e502b4e991677b53971277adfaf0a04a284f8e483e2553d0f83156b50) and qt 5.13.0.

Each change to bring the table in the example closer to my ideal is on a separate branch. This permits a simple diff between the master branch and the changed branch to determine the alterations I’ve made to the original example.

Branches

* fb8951a -  Converted composite primary key types to text (introduce_text_fields)
* 205492f -  Introduced constraints on composite primary key (constrained_composite_primary_key)
* c2f67c0 -  Introduced an unconstrained composite primary key (composite_primary_key)
* 184f5ed -  Removed QCoreApplication (master)
| * d731611 -  Converted ROWID table to a table (without_row_id)
| * 5dcc914 -  Removed QCoreApplication 
|/  
* ec024b1 -  White space change 
* 3bd46af -  Download of original source code 
* 2fe4f3e -  Initial commit

Conclusion

The table structure is not the problem.

Turns out a critical component of the code was missing:

 QSqlTableModel model(0, database());
 model.setTable("rast123");
 model.select();
 model.database().transaction();

Initialization of the QSqlTableModel was being done in a constructor. For some reason, this needs to be done again to prepare for the row insert. Doing so with the methods attached to this don’t have the desired effect.

March 8, 2021

A Look at ListView and C++ Models in Qt

  —Resources for using QML and C++ models.

I recently experimented with Qt and QML in an effort to construct an application that relies upon a QML ListView and a C++ model. This is a collection of resources that I found helpful. Article relies upon Qt 5.12.

I wandered around in the dark on some of this. The best path forward for learning is item 2 and 3.

Item 1 was my reviewing the difference between Model-View-Controller and the Model Delegate used by Qt.

Item 4 looks at whether I need to implement insertRows() when I found Qt’s documentation on subclassing QAbstractListModel a little vague. (I don’t.)

The winding path:

  1. A terrific Model View Controller (MVC) diagram provides a simple explanation of the Model-View-Controller pattern. This includes a diagram and a set of rules that are well presented and straight forward to understand.

    The nice part of this article is that it shows best practice and poor practice side-by-side.

  2. Models and Views in Qt Quick provides an overview on models and views in Qt. Qt uses a variant of MVC that combines the view and controller into a single entity and introduces a delegate. Importantly, the delegate is not a controller.

    There is some confusion regarding Qt’s implementation of MVC (see for example Why Qt is misusing model/view terminology?). That thread was useful to provide a contrast to a textbook MVC implementation.

    For me the answer lies in whether you choose to separate the view and controller. (My favorite reference for Model View Controller.) Qt combines them to create a Model Delegate pattern. The model delegate pattern combines the view and controller into a UI delegate.

  3. Using C++ Models with Qt Quick Views has a video showing how to create an application with QML and a C++ model.

    Explanation on creating read-only view and extending them to C++ models (around 9:31).

    The video shows how to connect the view and model together using a delegate in C++ (around 13:00 through to the end of the video).

    Importantly, the view (a QML ListView) is connected to the model in C++ (the TodoModel class) using the QML model keyword. The model is connected to the data, also in C++ (the ToDoList). The creation of the TodoList class starts at 20:30.

  4. Address Book Example provides a look at using a QTableView (my goal was a QListView). This example proved helpful in understanding whether the insertRows() method needed to be implemented or not. This example provided a look at what an implementation should look like.

    By default, insertRows() returns false if it’s not overloaded in a subclass of QAbstractListModel. The guidance in QAbstractListModel is you can overload this method (of course you can). It was light on details as to when you had to overload it.

Thinking about the QML and C++ model in terms of a Model Delegate instead of Model-View-Controller permits better reasoning about the implementation.

A source of confusion for me was the relationship between the QML QListView and the QAbstractListModel as it relates to model updates. Using C++ Models with Qt Quick Views puts the data in the backend, separate from the model (see video at 30:11). It follows the guidance in Models and Views in Qt Quick. Whereas, How to Use a QSqlQueryModel in QML puts data in the model’s constructor (see step 4 [implementation] and step 3 [use]).

The difference between the two approaches is unclear to me at this time. It’s unclear because I view the database as a persistent data store similar in purpose to the TodoList class in Using C++ Models with Qt Quick Views. Not sure why the rules would change.

(To be fair, when I wrote this article How to Use a QSqlQueryModel in QML was tagged as needs improvement.)

Here’s a list of starting points in the video from Using C++ Models with Qt Quick Views:

Highlight Time
Creating a read-only view 0:00
Extending view to C++ models 9:31
Creating the C++ backend class 20:30
Adding data through the view 45:30

The only confusing part of the video was the introduction of data into the constructor of the ToDoList class at 45:30. The ToDoList class looks like it’s part of the control. It’s a small point, especially in a tutorial, but adding data to ToDoList gives that class multiple reasons to change. In my opinion, a better approach is to extend ToDoItem to include a container class and have ToDoList use that container instead.

February 7, 2021

Working Agreements and Team Values

  —Using Working Agreements as Principles leads to Values Discovery

In Working Agreements as Principles, I discuss my continued belief that good working agreements are principles and provide an example on why. I’ve long suspected that this approach eventually leads to uncovering a team’s values as well.

I’ve been using the working agreement as a principle with the last two software teams I worked with. Their use with the first team, lead to the personal realization that I value good code review above some other activities. The second team took 14 months to get from principle to values in relation to code review. I believe that the introduction of BitBucket and transparency around code review prompted this change. (Both teams used BitBucket, although the first team started with Review Board.)

So here I am. Fourteen months after the introduction of the working agreement on code review I am about to embark on a discussion on values. Here’s out I’d like the discussion to play out:

  • Reiterate the working agreement. Our working agreement permits 2 or more reviewers to have a veto on merge to master and requires the author and reviewers work out differences.
  • Point out that the working agreement in intended to protect the master branch
  • Reiterate the importance of working agreement as a princple. Emphasize that merge to master without code review is discouraged, but if the reviewers think its appropriate then do it. If code review is a principle we adhere too then this should make people uncomfortable but their might be circumstances where it’s deemed appropriate.

The rationale for the contradiciton between “protecting” master and having reviewers give a ship it without review needs some explanation.

The contradiction is important to get people to express their belief. I want people to think “yeah, we could but should we?” In my view, it’s an important element of getting people to think about what they are doing.

In my situation, I have a situation where one person is merging a lot of code to master without review because we are bootstrapping a new implementation. This is making many people on the team nervous, as well it should. We are breaking basic Agile principles (particularly the one about working code) and our working agreement. But are we doing it for a good reason? Possibly. But that’s where the values and principles come in.

My hope is that the team will start to discuss their differences in relation to the working agreement. My hope is that the value conversation will drive better decision making. Decision making like: we should never do this under any circumstance or this situatin is unusual and it’s ok for a while.

Either way, it will be a great opportunity to see how the team’s bought into code review. And we might learn something about the “why” of how we build software together.

I’m hopefull about this dicussion.

January 9, 2021

How Playing with Rust Improved My C++

I recently took a tour of several programming languages. The objective was to try to implement the same solution in Rust, Haskel and Clojure. The important part of this exercise was that I hadn’t written anything in any of these languages previously.

I have to say that I really like Rust and the philosophy embodied in how that language approaches things. For example, using Cargo meant that I didn’t need to mess with a build system. With C++ I usually gravitate toward GNU Make or CMake both of which I’m beginning to find are a distraction from the implementation.

The most interesting thing that came out of my experience with Rust was their approach to structures and getters or setters.

One of the problems I have with a lot of C++ code is that the default impluse seems to be to create everything as a class. I prefer to use struct for certain things–usually PODs (Plain Old Data) but with an eye towards how the structure fits into the domain. The idea is that you start with a struct and build up your implementation until you have a strong case for a class.

For example, building up a data structure for managing people might look like this:

struct Person {
   string name;
};

A Person contains a collection of attributes describing a person. Those attributes might reside in a persistent store, such as a database.

struct SelectablePerson: Person {
   bool isSelected;
   SelectablePerson()
       : Person()
       , isSelected(false) { }
};

A SelectablePerson extends a Person to include a selected attribute. This attribute might be represented in a view where the person is selected (included) in a query against the database. The constructors are for convienience and ensure a consistent state for creating selectable people.

In C++, the argument for using a class starts to look appealing because the constructor is starting to push the boundary of a POD. In Rust, your choice is to develop traits to apply to Person. I’m going to take the position that SelectablePerson should remain a struct in C++. That argument rests in the Single Resposibility, Open-Closed and the Liskov Substitution principles (the SOL in SOLID).

In C++, a lot of people will argue you want getters and setters for the name and isSelected attributes. This usually drives them down the path of a class because of member visibility rules (i.e., make these attributes private). I’ve also had arguments with C++ programmers who insist that data members in a class be public because they don’t want to write getters and setters.

Rust has a different approach. By default, stucture members are private and you need to add the pub attribute to make them visible. What surprised me was that a lot of Rust examples forego getters and setters in favour of direct access if you make the attribute public.

The argument in favor of using a getter and setter is encapsulation. You can change the attribute without affecting clients. The counter argument is that the difference between

Person p;
p.name = "brian";

and

Person p;
p.set_name("brian");

isn’t significant. It isn’t significant because the logic surrounding this is just where you want the assignment statement. The first example, puts this assignment in every client class; the second does not.

Rust falls into the first example.

Importantly, I’m not saying you should open up your data members everywhere. I’m saying there is a time and a place for it and you shouldn’t just blindly make everything a class in C++.

Here’s an example where I think a class is appropriate.

class PeopleContainer {
public:
    /*! Container for SelectablePerson. */
    typedef std::vector<SelectablePerson> ContainerType;

    /*! @brief Construct the controller.
     */
    PeopleContainer()
        : container()
        , selected_count(0) { }
private:
    ContainerType container; //< A container for selectable people.
    size_t selected_count; //< A count of the number of people currently selected.
};

Why am I using a class here? The selected_count member requires additional logic to ensure that the number of SelectablePerson.isSelected values set to true is equal to the count. Neither Person nor SelectablePerson have this constraint.

In Rust, I’d introduce a countable trait to create an equivalent construct for the PeopleContainer.

So how did Rust improve my C++? It gave me a better understanding on why I was using struct instead of class in C++. It gave me a better understanding of the importance of SOLID in C++, particularly the Liskov Substitution principle. An important element of Liskov Substituion is type inheritance, not implementation inheritance. There is only type inheritance in these examples.

In all, I’m back to using C++ but I have only good things to say about Rust and look forward to the next opportunity to explore it.

December 11, 2020

Creating Better Designs

  —Another look at better designs.

In What is Good Design?, I explore what Christopher Alexander says about good design and what Robert C. Martin says are traits of bad design. Here I look at what Kent Beck has to say about Responsive Design.

Post includes an attempt to rationalize what Alexander, Brooks and Beck say on design. It’s a bit of a mess, but there are good references.

Kent says that good design permits a steady introduction of new features, it’s easy to test and tune for performance. The notion of good and bad design is symmetrical. Both reflect an aesthetic sense (you know it when you see it).

Kent has a talk on Responsive Design. The start of this talk goes into the approach he used when writing the book Smalltalk Best Practice Patterns.

Used a stack of index cards to track design decisions. This included constraints, decision points, etc. to create a powerful reflective tool. This approach showed that he only had four strategies for design.

Kent called this approach Responsive Design. Design gets interesting when you have feedback: how do you design with constraints. The responsive component plays into the feedback–am I going to take the current understanding of the design or am I going to respond to the feedback.

The goal of development is the creation of a steady flow of features. You need to balance the design–not too early and not too late. You need to take careful note of what and when to design. Design principles using the PermaCulture idea: benefically relating elements.

Kent Beck’s values in design:

  • simplicity (removing extraneous elements)
  • feedback (creating closed loops on the design)
  • community (being accessible to the user community)

Patterns are important for implementation and communication. It’s not just design patterns, but smaller patterns.

Principles provide assistance when encountering a novel situation. A paper on “dynamo”–Amazon’s key-value pair storage–has a great description of their principles. Principles rapidly shrink the design space–look for the universal principles. How do you choose these principles?

These strategies are:

  • Manage your leaps–move from the current design to the new design. Move your design in safe steps; not big steps.
  • Manage large leaps in parallel–operate two designs in parallel for a while helps minimize the size of a leap. This ensures that the system is always working and permits one to see progress.
  • Stepping stone–when you can’t get to where you want to go in a safe step. Use something to take you through intermediate steps.
  • Simplification–what is the least you can do to move forward? Try to eliminate things that are not germaine in the near term but balance against long term need to change.
  • Refactor–refactor of code is important.
  • Succession–there are successive patterns that are important to follow. See the paper by Kent Beck “First One, Than Many”. (Isn’t available on-line.)
  • Data–get data on your system and try to understand what it means.

Rationale design process:

Our illusion of control over software design is a dangerous conceit best abandoned.

Brooks in Design of Design and Alexander walk through the failure of a rationale design process. Brooks focuses on the need for iteration and feedback. Alexander focuses on the combinatorial explosion of options arising from even the simplest design tasks.

See Martin Fowler’s book on refactoring:

  • refactoring in the small, easy.
  • Refactoring in the large tends to be harder.
  • Most of the hard problems in programming turn out to be design problems.

See Alexander:

No single best design:

But design has a dark side. While there isn’t a single best design for any system, there are many poor designs for that same system.

Design for feedback:

Over-designing early leads to delaying feedback from real usage of the system, makes adding features more complicated, and makes adapting the design more difficult. By the same token, under-designing makes adding features more complicated, increases defects, and makes adapting the design more difficult.

You read somewhere that “fit” in design, according to Alexander doesn’t work in software. I think that’s the wrong way to look at it. Fit is about appropriateness to form and context. Fit in software includes form and context.

Consider the Singleton pattern. There are good examples on when to employ this pattern and when not to. If you employ the pattern you better be aware of the double-checked lock pattern if the singleton is used with multiple threads. If you employ the pattern in a single-threaded environment then you don’t need the lock.