Theory of Programming: Packaging Principles

Alexander Makarov / Yii core team

https://slides.rmcreative.ru/2022/hl-packages/

Who am I? 🤠

About me

  • 15+ years in: Java, PHP, JavaScript, etc.
  • Writer, speaker
  • Member of Highload and RIT program committees, head of PHP Russia program committee
  • OpenSource
  • Lead of Yii framework team, its representative at PHP-FIG
  • In the past: Siemens, Wrike, CleverTech, Stay.com, Skyeng
  • CEO of ASAPIRL

What's the plan?

In order to apply any principles correctly, you need to understand them.

Let's begin from the very basics...

Abstraction — generalization of essential, removal of non-essential (for the context).

What for?

To fit unfittable.

Source of all trouble
Short-term memory

TTL of the item is ~20 sec.

We cannot operate with high number of items:

  • 7±2 items (George Miller, 1989).
  • 4±1 (Cowan, 2001).
  • Number depends on items.

Trick: chunking

88003334434

8-800-333-44-34

Architecture is needed to deal with way too complex systems.

For our brain too complicated comes way too fast.

Layers!

Five entities in a layer. Perfect!

5 layers...

Abstraction is a tool, not a goal.

Abstraction is necessary Evil.

How to build an abstraction without making everything worse?

Cohesion / coupling

Any simple validation rules / markers?

SOLID

© 2000 Robert Martin

  • SRP
  • OCP
  • LSP
  • ISP
  • DIP

What is a "package"?

Grouped code items (classes).

  • Modules
  • Libraries
  • Microservices

Right questions?

  • How to design packages?
  • How to use packages (dependencies)?

Does Cohesion / coupling apply to packages?

Yes!

Can we use the same SOLID-markers?

Not really...

Package Cohesion (design)

REP, CCP, CRP

Package Coupling (usage)

ADP, SDP, SAP

Reuse-Release Equivalency Principle

The granule of reuse is the granule of release.

Group things, that are used by end user, together.


import java.io.ByteArrayOutputStream;
import java.io.IOException;

class Main {
  public static void main(String[] args) throws IOException{
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    os.write("my word".getBytes());
    
    os.writeTo(System.out);
  }
}
                    

import java.stream.ByteArrayOutputStream;
import java.exceptions.IOException;

class Main {
  public static void main(String[] args) throws IOException{
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    os.write("my word".getBytes());
    
    os.writeTo(System.out);
  }
}
                    

Common Closure Principle

Classes that are changed together are packaged together

Classes that are changed together by a maintainer should go into the same package.

i18n

  • Message translation.
  • CLI-tool to extract messages from code.

Common Reuse Principle

Classes that are used together are packaged together

If classes aren't used by end user separately, they belong to the same package.

Cache

  • Redis.
  • Memcached.

Sounds good?

Reality is harsh :(

Dr. Stefan Kluth, Max-Planck-Institut fuer Physik

On early stages focus on CCP and REP.

Acyclic Dependencies Principle

The dependency graph of packages must have no cycles

Cycles are causing cascading problems.

How to check for cycles?

  • Draw directed graph.
  • Look at it :)

There is clue/graph-composer.

But (PR #45) should be applied to exclude non-interesting packages.

The less dependencies, the simpler everything is...

How to break the cycle?

  • DIP — use dependency inversion via interface.
  • CRP — move the interface into a separate package.

Or rethink the package...

Stable Dependencies Principle

Depend in the direction of stability

You can't build a stable thing on an unstable base.

Can we measure (in)stability?

I = E / (E + A)

I — Instability. 1 — unstable, 0 — stable.

E — Efferent (outgoing, fanout) Coupling.
Number of classes out of the package the package depends on.

A — Afferent (incoming, fanin) Coupling.
Number of classes out of the package that depend on the package.

How to increase stability?

Stable Abstractions Principle

A package abstractness should increase with stability

Stable packages are abstract.
Flexible packages are concrete.

Can we measure abstractness?

A = Na / Nc + Na

  • A — abstractness. 0 — concrete, 1 — abstract.
  • Na — number of abstract entities in a package.
  • Nc — number of concrete entities in a package.
  • Abstract packages → stable: safe to depend on them.
  • Concrete packages → unstable: easy to change them.

D-metric

X — abstractness, Y — instability.

Good and bad

Sometimes 0, 0 is OK. Strings, arrays, stdlib.

D = | A + I − 1 |

Distance from main line.
0 is good.
1 is bad.

Tools

You can add it a pipeline.

Same as SOLID, these principles and metrics are not dogmas but tools.

Correct design results in explosive increase in the number of packages. It is scary.

Principles are there to keep you away from either left-pad or monolith.

These tools and principles should help you producing code that breaks less.

Questions time!