October 9, 2022

Good Note Taking

  —_How to Write Smart Notes_, by Sonke Ahrens

About a year ago I came across the book How to Write Smart Notes, by Sonke Ahrens. Up until this point, I’d kept my notes in my blog, a wiki and various other places. Ahren’s book outlines a note taking strategy invented by Niklas Luhmann called Zettelkasten.

Zettelkasten comprises an annotated bibliography and a slipbox containing your thought’s, ideas and questions on topics of interest to you. The claim is that using this tool and method enable the collection and organization of thoughts and learnin in a way that support deep insight and publication. I decided to use the approach and learned a lot about how to improve my note taking.

I’m fairly impressed with the results. The first example of a blog post I created using this method is the Single Responsibility Principle. I was impressed with the depth of the relationships I collected in relation to that principle.

To write that blog post I collecting 40 different ideas and wrote about 2,000 words to express those ideas. That post is about 800 words and does a nice job of covering my thinking on the subject. I’m impressed with the richness of the relationships between the principle and the concepts that drive it. It’s a good first result.

There are a great deal of resources available to describe Zettelkasten. If you are looking for a simple way to organize and collect information on topics of interest to you, this might be a worthwhile method to explore.

For me, key insights in using Zettelkasten were:

  1. The importance of creating a good annotated bibliography. I tend to write the bibliography in a file with key insights and page numbers. This lets me capture the insigh in my own words and find it again if I need it.

  2. The importance of writing notes about everything you read. I’ve created bibliographies for Tweets, books and research papers.

  3. The discpline of reflecting upon what you’ve read and connecting it to notes in the slipbox. This is key to learning and to the richness in the resulting writing.

The downside of using Zettelkasten was that I stopped publishing blog posts for about 18 months. (I have a queue of posts, so the gap doesn’t show up in my blog.)

It took a while to get used to this new way of working and that investment didn’t immediately pay off. It took time to capture, organize and relate my ideas in new ways. So have some patience.

September 10, 2022

The Single Responsibility Principle

  —What constitutes a single responsibility?

The Single Responsibility Principle (SRP) is part of the SOLID principles. I like to use SOLID to construct implementations and find it a useful tool to use in discussion about code. It comes up in interviews quite often–people list it on their resumes, so I ask them about it.

Most of the answers I get during those conversations are one-dimensional: SRP is about assigning one responsibility to a class. Yes, but which responsibility? How do you know if it’s the right responsibility?

I think of responsibility as a vector of change. Where the vector of change comprises both known and anticipated changes. In my view, multiple responsibilities are OK if those responsibilities are expected to change together and if their separation leads to a poorer implementation.

So what constitues a single responsibility? It’s the result of balancing the tension between reason to change, coupling and cohesion and separation of concerns.

Reason to change is driven by Parnas’ notion that a key criteria for decomposing systems into modules revolves around:

  • Difficult design decisions.
  • Design decisions which are likely to change.

Design each module to hide exactly one of these decisions. A module is a programming language concept that groups things together. (For example, a class, namespace, module, etc.)

Coupling and cohesion are usually discussed together but it’s important to consider them individually. Meyer’s notion is that low coupling and high cohesion tend to move in tandem and is the desirable state.

Coupling is a structural construct affecting modularity. It is structural in the sense that you don’t want things to depend upon or know about other parts of the design and implementation if they don’t have too.

Low coupling is characterized by

  • few interfaces that limit the number of interconnections between modules. The number connections to a module includes interfaces like procedure calls and data sharing, etc.

  • small interfaces that share as little information as possible and don’t leak abstractions.

Where coupling occurs explicit interfaces and explicit coupling should be used. Explicit interfaces and coupling rely upon the programming language to make them clear.

Cohesion is a conceptual construct. It is conceptual in the sense that you want like things to belong together so that you can reason about one thing at a time. High cohesion results a peaceful and honest coexistence between concepts.

The best types of cohesion arise from (good to best):

  • Communicational and informational cohesion occurs whenever elements that use the same data are grouped together.
  • Sequential cohesion occurs whenever elements that have a producer/consumer relationship are grouped together.
  • Functional cohesion occurs whenever elements that contribute to a single well-defined task are grouped together.

Separation of concerns is a conceptual tool that permits identifying differences within Jackson’s notion of problem, domain and application. In order to achieve separation of concerns for a problem you must identify the principle parts of the problem.

Identifying the principle parts of the problems, permits the identification of subproblems that need to be solved. Subproblems have different domains.

A domain is part of a whole, but exhibits two important properties:

  1. It has its own set of internal properties.
  2. It has its own set of behaviours.

Taken together these properties and behaviours are largely independent of everything else. For the structuring to work well the collection of phenomena that are private to each domain must be richer and more interesting than what is shared between domains.

You can view separation of concerns as defining layers of abstractions with each abstraction having distinct semantics. The semantics need to be consistent and different parts of the same abstraction should share the same semantics. That is the semantic gap between things should be small.

A single responsibility should yield a simple and easy to understand description of a domain. That domain’s description must be rich enough to be more interesting than what is shared between the domains. Multiple domains interact to solve problems and solutions to problems leads to useful applications.

Importantly, I’m not assigning single responsibility to a class. I’m assigning it to a domain.

A domain that exhibits a rich set of behavours that fit well together and whose proximity is not jarring. That domain may be represented using a class, but the driver for that class’ existence is it’s domain and the problem it solves in an application.

August 12, 2022

Don't Repeat Yourself and its Relation to Code and Knowledge

  —A look at DRY in relation to SPOT and OAOO

I got interested in the relationship between Don’t Repeat Yourself (DRY), code structure and knowledge. In my view, DRY is domain based (i.e., system-wide), but leads into structure (i.e., the prevention of code duplication).

The goal of DRY is to retain knowlege in a meaningful way. Meaningful in the sense it is

  • singluar (consists of one “thing”),
  • unambiguous (can be understood),
  • authoritiative (is a resource for containing knowledge) and
  • has representation (has an appropriate structure).

Importantly, it is authoritative not definitive (but it might be).

Definitive might look like a better word, but it implies complete knowledge. Authoritative is better because it implies the development of a shared resource to store, reflect upon and revise that knowledge. So DRY things provide a focal point for revision as you inch towards a definitive definition of that thing.

This means DRY fuses two concepts together: the collection of knowledge and its representation. Breaking it into its base forms you get:

  • Single Point of Truth (SPOT) is about a singular, unambiguous and authoritative source of knowledge. It applies to the domain the knowledge is generated from.

  • Once And Only Once (OAOO) is about representation. It applies structure to knowledge. Since OAOO comes into existence via refactoring it is also the process by which incremental improvement occurs.

Importantly, SPOT helps identify and organize information. OAOO is a structural activity that incrementally improves (but does not change) the implementation.

So how is it useful to include notions of SPOT and OAOO in DRY?

I’ve been reading a lot about how DRY might be bad (or overused) in tests and was wondering how this was possible. Most arguments have insisted that DRY can hide valuable information in tests. I haven’t seen other arguments against DRY so understanding DRY more deeply seem important to understanding when it’s wrong to apply it.

I’m not sure if my breakdown of DRY is accurate but it resonates. I’m not sure if I’ve quite put my finger on a formula for when it’s overused in tests.

July 14, 2022

Problem Solving

  —A Look at Problem Solving

In Problem Frames, I talk about how a discussion on Twitter lead me to examine Michael Jackson’s Problem Frames. Jackson’s Problem Frames are a way of identifying the key areas to address when developing an application. It’s value proposition is two-fold:

  1. Focuses you on the problem to solve.
  2. Provides a shape to the problem.

So, a problem frame, or rather a collection of them, helps you solve the right problem.

Some of this research led me into separation of concerns at the problem, domain and application level. Basically, good application design separates concerns at multiple levels. Separation of concerns is a layered approach that spans the gambit from what is it we are trying to do to how we structure the solution.

Importantly, semantics comes into play here. I’d characerize this as the things in each layer need to all mean the same things; semantic gap comes to mind. Or semantic distance, wherein like things should be collected together. It’s cohesive. At multiple levels.

It’s non-hierarchicl. A lot of methods imply heirarchy. The key point is that complex applications can have multiple “tops”. That is, they serve multiple purposes at the same time.

June 15, 2022

Problem Frames

  —A Look at Problem Frames

This Twitter thread drew my attention to Michael Jackson and Problem Frames. I hadn’t heard of Problem Frames before. The thread is worthwhile and contains other references to help explore a problem domain.

I read two papers on this topic.

  1. [Problems, Descriptions, and Objects][http://mcs.open.ac.uk/mj665/oois94a.pdf] and
  2. [Problem Decomposition for Reuse][http://mcs.open.ac.uk/mj665/Pkgrtr.pdf]

The first I would characterize as describing the motivation; the second as the method.

What makes these papers interesting, for me, is their focus on problem identification and description. The solution is secondary to solving the correct problem. You’ve heard this before, I’m sure.

The first paper is worth a read because it links problem exploration to Polya’s work. It characterizes topics in How to Solve It as focusing on problems to prove or problems to find. It proceeds to liken software problems as falling into the latter; problems to find.

Jackson call problems to find problem frames. He provides a nice connection between what Polya says and his motivation for problem frames:

By fitting a problem into a problem frame we should be classifying it precisely enough to be able to select an appropriate method for its solution.
The key requirement for a good problem frame is that it should be precise enough to give a really good grip on any problem that fits it.

The goal of a problem frame then is to characterize the problem well enough to select an appropriate method for it’s solution. He’s talking about a method for it’s solution, not a solution. That’s what makes the approach interesting–it’s modeled on Polya’s approach and he’s tailoring it to software problems. Jackson’s discussion goes on to worry about context–the application domain you are working in.

There is also a large section on Object-Oriented Analysis and Design that is worth a read.

Probably the key value in reading the first paper is the notion that focusing on the problem is more important than the solution. A good solution is a by-product of understanding the problem.

The other key point here is that the problem frame that guides to the solution must reflect the problem.

The second paper describes the problem frame and provides an explanation and example.