Debounce vs Throttle

Source: https://redd.one/blog/debounce-vs-throttle

A throttled function is called once per N amount of time. Any additional function calls within the specified time interval are ignored.

Examples:

  • Any consistent UI update after window resize
  • Performance-heavy operations on the server or client

A debounced function is called after N amount of time passes since its last call. It reacts to a seemingly resolved state and implies a delay between the event and the handler function call.

Examples:

  • Asynchronous search suggestions
  • Updates batching on the server

Big O Notation in 1 minute

See also:

Big O Notation is a mathematical function used in computer science to describe how complex an algorithm is.

There are two kinds of complexities: time and space.

Typically, there are three tiers (known as asymptotic notations) to solve for:

  • Best caseBig Omega or Ω(n)
  • Average caseBig Theta or Θ(n)
  • Worst caseBig O or O(n)

O(1) – Constant time complexity

One single step.

OPs
|
|
|
|
|
| .  .  .  .  .  .  .
|
+----------------------------- Elements

O(log n) – Logarithmic time complexity

If it takes 1 second to compute 10 elements, it will take 2 seconds to compute 100.

OPs
|
|                                     . 
|                    . 
|           . 
|      . 
|   .
| .
+----------------------------- Elements

O(n) – Linear time complexity

Loop of n steps.

OPs
|                   .
|                . 
|             . 
|          . 
|       . 
|    .
| .
+----------------------------- Elements

O(n²) – Quadratic time complexity

Loop inside a loop.

OPs
|                  .
|                 . 
|               .  
|            . 
|         . 
|     .
| .
+----------------------------- Elements

Xcode Project groups structure

Coming up next I will review briefly the main flaws of two common file grouping strategies used in Xcode projects. Then I will explain a grouping strategy that overcomes those flaws.

Strategies you should avoid

Grouping by component

Usually seen in monolithic projects and projects with lightweight architectures.

Description

  • All source files are grouped by component kind.

  • Each Component Group can be divided in subgroups according to some other criteria, for example the parent feature/functionality of the component.

Example

├── DataModels
│   ├── Login
│   ├── Feed
│   └── ...
├── DataSources
│   ├── Login
│   ├── Feed
│   └── ...
├── Models
│   ├── Login
│   ├── Feed
│   └── ...
├── Repositories
│   ├── Login
│   ├── Feed
│   └── ...
├── Views
│   ├── Login
│   ├── Feed
│   └── ...
└── ...

Review

The problem with grouping by component is that it breaks the Common Closure Principle (sort of Single Responsibility Principle at component-level).

The Common Closure Principle (CCP)

THE CLASSES IN A PACKAGE SHOULD BE CLOSED TOGETHER AGAINST THE SAME KINDS OF CHANGES. A CHANGE THAT AFFECTS A PACKAGE AFFECTS ALL THE CLASSES IN THAT PACKAGE.

Ultimately, components that need to interact with each other will be too distant, making it harder to locate the files you need to edit to perform a change in the code.

Grouping by business capability

Usually seen in projects where modularization reflects the layers of the architecture and projects where the architecture emphasizes the grouping of components by the screen they belong to.

Description

  • Presentation and Business layers source files are grouped by the Feature or UI flow (or Viper Module or Clean Swift Scene) they belong to.

  • Other source files, that are more prone to be used by more than one Feature group, may be organized (A) outside the Feature groups, using a different criteria, or (B) in subgroups of the Feature group they are more closely related to.

Example

(A) variant example:

├─ Data
│  ├── Models
│  └── Sources
├── Domain
│  ├── Models
│  └── Repositories
├── Scenes
│   ├── Feed
│   ├── Login
│   └── ...
└ ...

(B) variant with by component Scene subgrouping example:

├── Scenes
│   ├── Feed
│   │   ├── DataSources
│   │   ├── Models
│   │   ├── DataModels
│   │   ├── Repositories
│   │   └── Views
│   ├── Login
│   │   ├── DataSources
│   │   ├── Models
│   │   ├── DataModels
│   │   ├── Repositories
│   │   └── Views
│   └── ...
└ ...

(B) variant without further Scene subgrouping example:

├── Scenes
│   ├── Feed
│   ├── Login
│   └── ...
└ ...

Review

The problem with grouping by business capability is that, depending on how the files inside the Feature groups are organized, it will suffer from the same problem already exposed for the grouping by component approach.

In its shallowest form, where Feature groups members are not organized in subgroups, two files that need to change together will be close to each other, as implied by the Common Closure Principle. But that approach breaks the Common Reuse Principle (sort of Interface Segregation Principle at component-level).

The Common Reuse Principle (CRP)

THE CLASSES IN A PACKAGE ARE REUSED TOGETHER. IF YOU REUSE ONE OF THE CLASSES IN A PACKAGE, YOU REUSE THEM ALL.

Ultimately the lack of a folder hierarchy will make it more difficult to locate a particular component inside a group and to understand how it relates to the other components in that group.

Proposed strategy

Grouping by relative visibility

Effective in projects wholly modularized by business capability (higher module granularity by technical capabilities or functional objectives is fine) and projects where architecture emphasizes single-direction communication between components.

Description

  • Source files are organized in a hierarchical tree structure that represents the relative visibility between architecture-defined components.

  • Top-level nodes (groups) are reserved for the outermost components of each layer (i.e. components visible to adjacent layer).

  • Inner nodes (subgroups) represent dependencies of the parent node (i.e. components the parent group component depends on).

Example

├── Feed
│   ├── Models
│   │   └── DataModels
│   ├── Repositories
│   │   └── DataSources
│   └── ...
├── Login
│   ├── Models
│   │   └── DataModels
│   ├── Repositories
│   │   └── DataSources
│   └── ...
└ ...

Review

Advantages of grouping by relative visibility include:

  • It does not break any of the package cohesion principles.
  • It has a predictable group hierarchy inside each module or feature group.
  • It helps to spot undesired coupling between components.
  • It makes easier to focus only in the files you need to edit to perform a change in the code.

See for instance what the Feed screen from the previous examples could look like following this grouping strategy, implemented as a module/target and using MVVM with Use Cases and Repositories:

Linking C libraries in SPM

When defining a C/C++ target with SPM, if you need to use a library from /usr/local, you can pass the required C compiler and linker flags from your Package.swift:

// swift-tools-version:5.1

import PackageDescription

let package = Package(
    name: "SomePackage",
    targets: [
        .target(
            name: "SomeCTarget",
            cSettings: [.unsafeFlags(["-I/usr/local/include/"])],
            linkerSettings: [.unsafeFlags(["-L/usr/local/lib", "-lfltk"])]
        )
    ]
)

Using system libraries in SPM

If you need to use a system provided library such as ncurses, you can import it through Darwin module:

import Darwin.ncurses

Then you just need to link it from your Package.swift:

// swift-tools-version:5.1

import PackageDescription

let package = Package(
    name: "SomePackage",
    targets: [
        .target(
            name: "SomeExecutable",
            dependencies: ["SomeLibrary"]
        ),
        .target(
            name: "SomeLibrary",
            dependencies: [],
            linkerSettings: [.linkedLibrary("ncurses")]
        )
    ]
)

Generate a Swift interface from an Objective-C header

from Terminal

echo -e "import CoreData\n:type lookup CoreData" | swift

As seen in StackOverflow.

from Xcode

  1. ^ + ⌘ + left-click (or ⌘ + left-click > Jump to Definition...) on the name of the type whose interface you want to generate (e.g. NSEntityDescription).
  2. From the Jump to Definition list, choose the entry from the platform you are targeting (e.g. macOS 15.0 ▸ CoreData ▸ NSEntityDescription.h:26 ).
  3. Go back to the previous swift file (Jump Bar’s CoreData>NSEntityDescription`).
  4. At this point you will see the generated Swift interface for the type’s header.

from Safari

Private GitHub repository setup for teams

Pull request template

You can add a .github/PULL_REQUEST_TEMPLATE.md file like the following one to provide a loose standard way of creating pull requests:

#### 🎩 What? Why?

#### 📋 Developer checklist
- [ ] Add entry to `CHANGELOG.md`
- [ ] Check for warnings
- [ ] Localize strings
- [ ] Manual test
- [ ] Unit tests
- [ ] Snapshot tests
- [ ] UI tests

#### 🎯 How should this be manually tested?

#### 📌 What are the relevant tickets?
https://ORGANIZATION.atlassian.net/browse/PROJECT-

#### 📷 Screenshots (if appropriate)

#### 👻 GIF
![](http://johnjohnston.info/oddsandends/ds106gif)

Team collaboration labels

Default GitHub labels are really well set for open-source projects and when using GitHub’s integrated issue tracker. But, if you are using GitHub only for pull requests and code reviews, you can try to use a more specific configuration like the one proposed below:

  • : This branch is pointing to an integration branch.

  • : Release blocker, maximum priority.

  • : Its the base branch of a dependency pull request.

  • : Its base is an integration branch.

  • : Work in progress, won’t merge.

  • : Check this new idea.

Coupling and Cohesion measurements

Measurement is the first step that leads to control and eventually to improvement. If you can’t measure something, you can’t understand it. If you can’t understand it, you can’t control it. If you can’t control it, you can’t improve it.

H. James Harrington

There is much to be said about Cohesion and Coupling.

You already heard the old mantra: low coupling, high cohesion.

But the key question is Are There Metrics For Cohesion And Coupling? .

Well, there are.

For cohesion, see for instance LCOM4 (Lack of Cohesion of Methods):

For coupling, see how you can measure afferent coupling and efferent coupling and use them to calculate the (in)stability of a class:

Software Metrics insights

What Happened to Software Metrics? insights on Software Metrics evolution make for an interesting read.

The authors of the aforementioned article "asked a panel of 7 software metrics experts 11 questions to help explain the last 40 years of software measurement and where they believe we stand today".

In the article you can read their opinions about different static and dynamic metrics.

Examples of static metrics discussed in the article:

  • size
  • coupling
  • cohesion
  • complexity
  • testability

Examples of dynamic metrics discussed in the article:

  • run time performance (time and space requirements)
  • test coverage achieved for specified test criteria
  • number and frequency of defects discovered (or failures reported) in a system after release