Make notes visible

I have written some notes on some of my objects. I would like to see the note next to the label all the time. Ie when it’s open as a document, or printed. As it is now you have to hover the mouse over the object to see the note.

Is this possible?

If not, how do you create notes that are visible all the time (I’m using Auto Layout, otherwise it would be quite simple of course)?

Thanks,
Andreas

Rough first sketch of a script which creates/updates a ‘visible notes’ layer on top of a diagram.

(When the script is run, it updates the contents and position of a set of note shapes (creating them if they do not yet exist), which match the position and notes field text contents of shapes in the diagram below).

Can be run in between Auto-Layout repositioning, and will move notes to follow their base shapes, but needs Auto-Layout to be switched off.

(Paste into Script Editor, and choose JavaScript from the language selector at top left, before running)

NOTE: This is a pull script – copies text from the note fields of the underlying shapes into visible notation shapes.
If you wanted to write directly into the visible note shapes, and push the new text back into the notes fields of the underlying shapes, you would need to sketch a sister push script to go with this.

All Rube Goldberg or Heath Robinson territory, of course :-) This should really be built into the app.

// DRAFT sketch of "visible notes"

// CREATE OR UPDATE A "NOTATION" LAYER OVER A DIAGRAM


// 1. The script finds or creates a "notation" layer on top of the diagram in the front canvas
// 2. For each shape in the diagram which has a note:
//        The script:
//             - finds or creates a visible linked note shape
//             - updates its text contents and position to match the underlying shape
// 3.  The format of the note shape, and its x, y offsets from the base shape,
//     can be adjusted in the options at the end of the script

// N. B. Each time the script is run, the note shapes are repositioned and textually updated to
//         to show the contents of the linked shape's notes,
//       BUT you will need to switch off Auto-layout while you are using the script

//         The visibility of the notation layer can, of course, be toggled in the sidebar.

//          The workflow would have to be:
//            1. Switch on and adjust Auto-layout to get the positioning you want
//            2. Switch Auto-layout OFF again
//            3. Run this script to update the visible annotation layer
//

(function (dctOptions) {
    'use strict';

    // (a -> b -> c) -> [a] -> [b] -> [c]
    function zipWith(f, xs, ys) {
        return xs.length === ys.length ? (
            xs.map(function (x, i) {
                return f(x, ys[i]);
            })
        ) : undefined;
    }

    var og = Application("com.omnigroup.OmniGraffle6"),
        ds = og.documents,
        d = ds.length ? ds[0] : undefined;

    if (d) {
        var cnvs = d.canvases,
            cnv = cnvs.length ? cnvs[0] : undefined,
            diagramLayers = cnv ? cnv.layers.whose({
                _not: [{
                    _match: [
                        ObjectSpecifier()
                        .name,
                        dctOptions.notationLayerName
                    ]
                }]
            }) : undefined;

        if (diagramLayers) {
            var diagramShapes = diagramLayers.shapes,
                shapesWithNotes = diagramShapes.whose({
                    _not: [{
                        _match: [ObjectSpecifier()
                            .notes, null
                        ]
                    }]
                });

            //return shapesWithNotes.length;

            if (shapesWithNotes.length) {

                var noteLayers = cnv.layers.whose({
                        _match: [
                            ObjectSpecifier()
                            .name,
                            dctOptions.notationLayerName
                        ]
                    }),
                    // Notation layer - found or created
                    noteLayer = noteLayers.length ? (
                        noteLayers[0]
                    ) : (cnv.layers.unshift(og.Layer({
                        name: dctOptions.notationLayerName
                    })), cnv.layers[0]),
                    noteShapes = noteLayer.shapes;

                var lstTargetID = noteShapes.userData()
                    .map(function (x) {
                        return ~~x.noteFor;
                    }),
                    lstNoteID = noteShapes.id();

                //return lstTargetID


                // Update or create the annotation sattelite of
                // every annotated diagram shape
                var lstNotes = shapesWithNotes()[0]
                    .map(function (shp) {
                        var idShape = shp.id(),
                            iPosn = lstTargetID.indexOf(idShape),
                            blnFound = iPosn !== -1;

                        if (blnFound) {
                            var noteShape = noteShapes.byId(
                                lstNoteID[iPosn]
                            );
                        } else {
                            var noteShape = og.Shape(dctOptions.noteStyle);

                            noteLayer.graphics.push(noteShape);
                            noteShape.userDataItems.byName('noteFor')
                                .value = idShape.toString();
                        }


                        // AND NOW UPDATE:

                        // 1. TEXT
                        noteShape.text = shp.notes();

                        // 2. POSITION
                        noteShape.origin = zipWith(
                            function (a, b) {
                                return a + b;
                            },
                            shp.origin(),
                            dctOptions.originDelta
                        );

                        return noteShape.id();
                    });

                return lstNotes;
            };
        }
    }
})({
    notationLayerName: "notation",
    noteStyle: {
        size: [150, 25],
        thickness: 0.25,
        strokeColor: [0.6, 0.6, 0.6],
        shadowBeneath: true,
        autosizing: "vertically only"
    },
    originDelta: [0, 50] // simple offset from base shape origin
});

1 Like

PS to adjust the formatting of the edges, shadows, shades etc of the note shapes, you can select a shape that is manually formatted to the style you want, and then inspect the JavaScript for Automation encoding of the various properties by looking at the Result panel output of a script like this:

(The relevant key-value pairs can be copied and added to the options at the bottom of the notation layer script)

Source:

(function () {
    'use strict';

    var og = Application('com.omnigroup.OmniGraffle6'),
        ws = og.windows.whose({
            _not: [{
                document: null
            }]
        }),
        w = ws.length ? ws.at(0) : undefined,
        cnv = w ? w.canvases.at(0) : undefined,
        slns = w ? w.selection() : [],
        lng = slns.length;


    return lng ? slns[0].properties() : undefined;
})();
1 Like

Update: a slightly more ambitious version, allowing a workflow in which diagram notes can be edited in the display text of their linked notation-layer visible satellites, with and texts edits synced back to the note fields of the diagram shape when the script is run.

Test it before you use it, and make sure that you can see the limits of the very simple sync that it does:

In addition to:

  • the diagram note, and
  • the display text of the linked satellite shape,

the script keeps an additional (third) copy of the diagram note text in the note field of the satellite shape.

This gives a triangle of texts, with 3 edges of possible difference.

  • All three edges match – no textual change, the script just repositions the satellite, to put it next to the corresponding diagram shape
  • No edges match – edits must have been made in multiple places – the script prompts the user to to choose between versions
  • One edge matches – two versions are unchanged, one is different, the script assumes that this is the newest version, and updates the others.

i.e.

You should be able to edit the note text, between script runs, either:

  1. in the base shape’s note field, or
  2. the notation-layer satellites’s display text, or
  3. the notation-layer satellite’s note field.

but you should of course, try not to edit the same in two different places between script runs.

// DRAFT sketch of "visible notes"

// ver 0.7 Simple push + pull version
//  The script find or creates a notation layer above the canvas of the
//  the active window

//         NOTE: this very rudimentary push + pull scripted workflow
//              makes use of the note layer satellite's OWN note field
//              to keep a third copy of the note text, for comparison
//              and detection of new edits.

// CREATE OR UPDATE A "NOTATION" LAYER OVER A DIAGRAM


// 1. The script finds or creates a "notation" layer on top of the diagram in the front canvas
// 2. For each shape in the diagram which has a note:
//        The script:
//             - finds or creates a visible linked note shape
//             - updates its text contents and position to match the underlying shape
// 3.  The format of the note shape, and its x, y offsets from the base shape,
//     can be adjusted in the options at the end of the script

// N. B. Each time the script is run, the note shapes are repositioned and textually updated to
//         to show the contents of the linked shape's notes,

//         The script switches off Automatic Layout, in order to position the notes

//         The visibility of the notation layer can, of course, be toggled in the sidebar.

//          The workflow would have to be:
//            1. Switch on and adjust Auto-layout to get the positioning you want
//            2. Switch Auto-layout OFF again
//            3. Run this script to update the visible annotation layer
//

(function (dctOptions) {
    'use strict';

    // (a -> b -> c) -> [a] -> [b] -> [c]
    function zipWith(f, xs, ys) {
        return xs.length === ys.length ? (
            xs.map(function (x, i) {
                return f(x, ys[i]);
            })
        ) : undefined;
    }

    var og = Application("com.omnigroup.OmniGraffle6"),
        ds = og.documents,
        d = ds.length ? ds.at(0) : undefined;

    if (d) {
        var wins = og.windows.whose({
                _not: [{
                    _match: [ObjectSpecifier().document, null]
                }]
            }),
            cnv = wins.length ? wins.at(0).canvas() : undefined,
            diagramLayers = cnv ? cnv.layers.whose({
                _not: [{
                    _match: [
                        ObjectSpecifier()
                        .name,
                        dctOptions.notationLayerName
                    ]
                }]
            }) : undefined;

        if (diagramLayers) {
            var diagramShapes = diagramLayers.shapes,
                shapesWithNotes = diagramShapes.whose({
                    _not: [{
                        _match: [ObjectSpecifier()
                            .notes, null
                        ]
                    }]
                });

            if (shapesWithNotes.length) {
                var noteLayers = cnv.layers.whose({
                        _match: [
                            ObjectSpecifier()
                            .name,
                            dctOptions.notationLayerName
                        ]
                    }),
                    // Notation layer - found or created
                    noteLayer = noteLayers.length ? (
                        noteLayers[0]
                    ) : (cnv.layers.unshift(og.Layer({
                        name: dctOptions.notationLayerName
                    })), cnv.layers[0]),
                    noteShapes = noteLayer.shapes;

                var lstTargetID = noteShapes.userData()
                    .map(function (x) {
                        return x !== null ? ~~x.noteFor : '';
                    }),
                    lstNoteID = noteShapes.id();

                //return lstTargetID


                // Update or create the annotation display satellite of
                // every annotated diagram shape
                var lstNotes = shapesWithNotes()[0]
                    .map(function (shp) {
                        var idShape = shp.id(),
                            iPosn = lstTargetID.indexOf(idShape),
                            blnFound = iPosn !== -1;

                        if (blnFound) {
                            var noteShape = noteShapes.byId(
                                lstNoteID[iPosn]
                            );
                        } else {
                            var noteShape = og.Shape(dctOptions.noteStyle),
                                strNote = shp.notes();

                            noteLayer.graphics.push(noteShape);
                            noteShape.userDataItems.byName('noteFor')
                                .value = idShape.toString();
                            noteShape.notes = strNote;
                            noteShape.text = strNote;
                        }


                        // AND NOW UPDATE:

                        // 1. TEXT
                        // The script keeps the note text in three places
                        // (N)ote – the note field of the diagram shape
                        // (V)isible – the display text of the note layer shape
                        // (Intermediate) – the note field of note layer shape

                        // Keeping an extra 'intermediate' copy allows for
                        // simple guesses about which version changed most
                        // recently:

                        // - If all 3 copies match, no need for update.
                        // - If 2 copies match, the differing third is assumed
                        //   to be a new edit, and copied to the others
                        // - If no copies match, a dialog asks the user to
                        //   make a choice

                        var strNote = (shp.notes() || '')
                            .trim(),
                            strInter = (noteShape.notes() || '')
                            .trim(),
                            strVisible = (noteShape.text() || '')
                            .trim();

                        var blnNI = (strNote === strInter),
                            blnIV = (strInter === strVisible),
                            blnVN = (strVisible === strNote),
                            intMatches = [blnNI, blnIV, blnVN]
                            .filter(function (x) {
                                return x;
                            }).length;

                        // 3 matches -> stet
                        // 2 matches (we are in the wrong universe. dance)
                        // 1 match -> treat the non-matching copy as new
                        // 0 matches -> ask the user what is going on
                        if (intMatches < 3) {
                            if (intMatches < 1) {
                                // Prompt for choice
                                var a = Application
                                    .currentApplication(),
                                    sa = (
                                        a.includeStandardAdditions =
                                        true,
                                        a
                                    );
                                sa.activate();
                                var dctChoice = sa.displayDialog(
                                    'HIDDEN:\n\n\t' + strNote +
                                    '\n\nVISIBLE:\n\n\t' +
                                    strVisible +
                                    '\n\nOTHER:\n\n\t' +
                                    strInter +
                                    '\n\nChoose version:',
                                    dctOptions.dialog
                                );

                                var blnVisible = (
                                        dctChoice
                                        .buttonReturned === "Visible"
                                    ),
                                    blnNote = (
                                        dctChoice
                                        .buttonReturned === "Hidden"
                                    ),
                                    blnInter = (
                                        dctChoice
                                        .buttonReturned === "Other"
                                    );

                            } else {
                                var blnVisible = blnNI,
                                    blnNote = blnIV,
                                    blnInter = blnVN;
                            }
                            if (blnVisible) {
                                shp.notes = strVisible;
                                noteShape.notes = strVisible;
                            } else if (blnNote) {
                                noteShape.notes = strNote;
                                noteShape.text = strNote;
                            } else if (blnInter) {
                                noteShape.text = strInter;
                                shp.notes = strInter;
                            }
                        }

                        // 2. POSITION
                        //    (Fruitless with Automatic Layout ON)
                        cnv.layoutInfo.automaticLayout = false;

                        noteShape.origin = zipWith(
                            function (a, b) {
                                return a + b;
                            },
                            shp.origin(),
                            dctOptions.originDelta
                        );

                        return noteShape.id();
                    });

                return lstNotes;

            }
        }
    }
})({
    notationLayerName: "notation",
    noteStyle: {
        size: [150, 25],
        thickness: 0.25,
        strokeColor: [0.6, 0.6, 0.6],
        "shadowFuzziness": 2,
        "shadowColor": [0, 0, 0],
        shadowBeneath: true,
        shadowColor: [
            0.000000,
            0.000000,
            0.000000,
            0.250000
        ],
        autosizing: "vertically only"
    },
    originDelta: [0, 50], // simple offset from base shape origin
    dialog: {
        buttons: [
            'Hidden',
            'Visible',
            'Other'
        ],
        defaultButton: 'Hidden',
        withTitle: 'Choose between edits',
        givingUpAfter: 30
    }
});

1 Like

If you can develop this using a single occurrence of the Notes, in the satellite only, rather than three occs, it would be very useful.

Feel free :-)

The source is there …

It is two different things.

  1. A Note is an item that appears in a balloon when you hover over an object. It disappears when you move away from the object. We don’t want to lose that. A Note is not a text object.
  2. Text that you “see next to the label all the time” is simply a text object, not a Note.

Yes it is, once you understand the above.

There are a few different ways you can get what you want … it depends on precisely what you want, how you wish the text object to appear “next” to the object, whether Auto-Layout is to be used; etc. Here is one, this works with Auto-Layout (eg. left-to-right) in mind.

  1. Place the text object precisely next to the object that it relates to. Line it up the way you want (eg. to the right of the object; 0.4cm space; the tops aligned; etc)
  2. Group the object and the text object
  3. Make all line connections to the object (not to the text object)
  4. Auto-Layout as per your selected template

If it excludes duplicated text, yes.

As is, definitely not.

Thank you for the opportunity.

From my perspective, I would never publish something that is a mass of duplication, because that breaks one of the cardinal rules of handling data, as well as of software design. So if I did publish something aloing these lines, I would design it and build it within those engineering standards. It is a great idea, but as it stands, it is unusable, sub-standard, non-compliant. It is at the prototype level, not at the publication level. So really, the opportunity is for you, the initial designer, to note its utility, from the comments here, to bring it up to standard, and publish it.

I am too busy with other projects. And OG Notes work just fine for me, within the existing scope. If and when a decent satellite Notes facility becomes available, I would use it.

:-)

Not sure that what you suggest is feasible, given the structure of the OG object model.

But if you want to experiment, go for it !

(I would be more than delighted to be proved wrong :-)

  1. Let’s get that out of the road, right away. I am not here to prove anything to anyone. You are more than capable, given the content of your posts; the scripts; etc.
  2. This conversation is for heavy-duty users of OG, and the developers (who are not listening).

Very important point.

  1. What structure ? There isn’t any structure (unless they have a private definition of the word “structure”). It is a barf-bag of tag-value pairs. With massive duplication, data duplication as well as tag duplication. The plist file is massive. When they went from OG4 to OG5, the file quadrupled in size. OG6 is unusable, so I have not used it much, but on the face of it, the file size doubled again. Pathetic.
  2. The absence of (a) Structure, and (b) Normalisation of the structure, is the single greatest hindrance to the product, and to its progress (versions, features, etc)
  3. It is also the single greatest hindrance to all users who use it beyond a simple, one-page diagram.

The notion of simple but good-looking diagrams is partly Apple’s dictum, implemented in OSX and therefore partly Apple’s insanity. The idea of reducing OSX products down to the capability of iOS is backward and short-sighted, not surprising, given the schizophrenic CEO. The days of Steve Jobs are long gone.

But as far as OG is concerned, they simply do not appreciate the power of the product, and its utility. They do not have a long-term perspective or goal. OG just “progresses” in fits and starts, servile to OSX changes (fits and starts) and to the users who scream the loudest.

Second, OF and other products have taken over the front stage, and OG is severely neglected.

To understand what I am saying, it may be helpful to understand what a serious product with a long-term focus and commitment to heavy-duty use would be, so allow me to paint that picture.

  1. The central article is the database that contains the diagram (all objects; characteristics; vectors; etc). It is rendered (a) in memory, and (b) as the plist file.
  2. Since the date in well past 1970, it should be a Relational Database (Codd’s Relational Model, not the pretenders).
  3. That would allow any user to use the database, any way they want (ie. not restricted to the ways that Omni thinks that it might be used, which is myopic anyway). Scripts would be simpler, without the headaches, such as this example.
  4. The database (in both memory and the plist file) would have Structure. It would be the smallest footprint, the fastest. And therefore the product itself would have the smallest footprint and be the fastest (as far as data access is concerned).
  5. One of the cardinal requirements of a database is elimination of data duplication. One fact in one place. That eliminates a million or so problems.
  6. Second last but not least, one of the requirements of a long term focus is not removing features (OG4 features are removed from OG5). Therefore users cannot rely on OG features. A serious product would have backward compatibility. They don’t even know the meaning of that, let alone the relevance of that.
  7. Last but not least, after so many versions, the GUI should have settled down by, and should be more consistent. It isn’t. Just two egs of many: <escape> does one thing in one box and something different in another box; some dialogs require an <ok>, others don’t.

The problem is, each “development team” for each version treats the product as if they were building it for the first time, without reference to the previous version (which put Omni on the map). Each version introduces new and “interesting” problems and bugs that the previous version did not have. It is corporate suicide.

Instead of the above, we have a flat file with massive duplication, and all the problems that are consequent to the absence of Database implementation, the absence of Structure; etc

  • The product is very slow once your diagram becomes complex, or goes beyond a few pages.
  • Access to the objects (in both memory and the plist file) is crippled.
  • Heavy duty use, or use beyond the notion Omni has for the product, is severely crippled.

Example

From an OG5 diagram such as this:

  • Data Model
    Given as PDF
    This example is Table-Key level, not completely Normalised, tiny (a real DM would have one hundred or more tables)

… with a few key strokes, I produce these:

(For completeness, the PDF with Export/IncludeNotes is:

  • Data Model mit Noten
    PDF Notes do not work inside a browser, if you have the interest, download the PDF.
    One has to open each Note indicator, but that is a PDF, not OG, limitation.
    )

I trust you can imagine that I do something along the same lines using SVG for websites.

The problem is, the whole exercise is fraught with problems, due to the absence of a Database, of Structure.

  • Eg. I have not cracked the connectivity of lines, so the Relations are primitive placeholders, which have to be manually cut-pasted from the separate entires. Therefore the Predicates and DDL are incomplete, one has to manually mess with their hair.
  • If there were a Database, a Structure, the exercise would be straight-forward, and the Predicates and DDL would be complete, no manual work would be required.

For understanding:

  • Note that you take an object approach (think in terms of objects, and what can be done from an object-centric position). Therefore your scripts are object-centric, and the scope of the products are thusly limited.
  • Whereas I take a Relational or Set-based approach: I handle the entire plist file once, extracting all objects and their properties, and produce the three required files. (There is more, I am keeping this example simple.)

Continuing

Just look at the TemplateChooser. Full of duplication, and therefore full of bugs. The absurd SharedLayers. Full of duplication, and therefore full of bugs. Instead of fixing the duplication, the product forces the user to reduce themselves to handling duplicates, a burden the Computer Science world was released from in the 1960’s.

Therefore, granted, OG has no structure, no database, and therefore the objects are difficult to deal with beyond their simplistic initial scope. From the example provided, I trust you can see, sure, it can be done, but it is severely hindered.

The notion you have for Notes/Satellites is an excellent idea. But it must be implemented, to work within those imposed parameters, and without either adding more duplication (and therefore more problems) or maintaining the products duplication (and therefore maintaining the current problems). It must be implemented without duplication. Here you have three copies of the Notes text. That is one original plus two duplicates. If you can implement it such that:

  • the Notes appear in a satellite window,
  • as a full Extension
  • the Notes text appears once, in that window, and in no other windows
  • that is the one-and-only place it is manipulated (ie. the user avoids the Inspector/Property/Note when usiing your Extension)
  • the Notes appear in the diagram in the usual manner (wherever, and according to the set characteristics)

To be clear, when using your Extension, for each Extended Note, there will be one Satellite file that is dependent on the OG diagram file, in the same directory, named something like:

  • OG_Diagram_ObjectName.plist

and having:

  • either (a) a tag-value non-structure like the current OG Note, the current barf-bag
  • or (b) a decent Structure of plist tag-values for a Note.

Then you will have a serious, feasible, Notes Extension.


Again, if Omni had a long-term product focus, if they appreciated the power of OG, this feature would be a part of the product, not an Extension by an advanced user. The notion of a central diagram, plus satellite diagrams, would raise the product up to the level required for serious use, to the level of a Design Tool (rather than a mere drawing tool), such as:

  • a data modelling tool (Document = Export PDF/text, file plus Satellites)
  • a website implementation tool (Implement = Export SVG, file plus Satellites).

TLDR, I’m afraid, but I do recommend George Steiner’s Real Presences, which argues well that valuable commentary is always in the same mode as the object of comment.

Derived, modified or alternative code is always useful, or at the very least, interesting.

No idea what you mean by that, or how it applies here.

Attention is a precious resource - people spend it when the deal looks good.

The only useful commentary on code is more useful code - people would love to see code contributed by a guru, but they may not, I fear, devote much attention to long screeds in English :-(

True. One can spend only what one has.

Spoken like a true coder.

Evidently you have a private definition for “commentary”. I would accept that:

  • a commentary on code is code derived from it

but the notion of:

  • the only useful commentary on code is more useful code

is quite absurd. Humans have five senses and an intellect. We are not limited to reading code; and only code; so help me code, we can read other things, we can understand drawings, etc.

Further, it implies that the initial code is useful. It isn’t.

Architecture & Design

The realm of Architecture & Design is above the realm of code. Once one gets familiar with that, one’s code improves, drastically, it exists in two realms. It eliminates the code-and-keep-changing-code that coders are used to. One achieves the position where one can code-once-and-forget. Learning Architecture & Design does, however, require an attention span. A fair amount of reading and diagramming is involved.

[quote]people would love to see code contributed by a guru, but they may not, I fear, devote much attention to long screeds in English
[/quote]
Not people, coders. The notion that you speak for people is too hilarious to respond to.

People, who have knowledge of all the aspects of software implementation, who are not limited to a code-is-God context, can read articles in English. Therefore they code better. They Normalise their code. Their code does not get thrown out and replaced or “refactored” every month. Designed code has a much smaller footprint than coders’ code, and runs hundreds of times faster.

Eg. you have coded and published a Note script that is not useful to me, for several reasons (duplication being just one). No doubt it is useful to others, but I cannot speak for others. I have defined what a useful Note Extension would be. But you can’t read about what would make your code useful. You want me code from your code.

  • Your code is single-object-centric.

  • Architecture & Design is the opposite, it is system-centric. That means taking all the objects into account, and integrating them fully, such that no code segment is duplicated. One needs to understand Hierarchies; the objects in the context of the whole production; Composition/Decomposition; etc, rather than simple inheritance.

  • Therefore, even if I did code something, I couldn’t use your code, it would be new code, in a different, far-off realm.

  • That is the commentary re your code.
    But in your state, you can’t read the English commentary, you want a code commentary. Ok.

Only if the initial code is useful.

I gave an example of the problem, and the solution, the code for which most people find interesting. You can’t even figure out the code (object-centric or otherwise) that is required to produce this from this.

I would give you the code, but:

  • it is a bit long, and you have the attention span issue. I’m afraid you would find it too long, can’t read.

  • In any case, you want code that validates your code, and this code, being Architected & Designed, does quite the opposite. I would prefer not to offend.

  • Third, it is in a language that is foreign to you, one that is procedural, and contextual, and supports objects.

So I better not, for three reasons.

I would recommend Kruger & Dunning’s papers on metacognitive skills. Not surprisingly, the creatures that pass for “scientists” these days attacked it, so they performed a second study that focussed on the “issues” raised, and ended up confirming their initial findings. If you can’t find them on the internet, they are here: paper 1; paper 2.

They are essential reading for anyone in IT, especially these days, with so many people who have just one tool in the toolbox (if all you have is a hammer, everything looks like a nail - Abraham Maslow in Law of the Instrument ).

If you find those interesting, let me know, I have a couple more that might interest you.