Progressive disclosure of complexity in programming language design
Progressive disclosure of complexity (PDC) is a concept, originating in the field of UI design, that dictates that the user interface should evolve naturally, from simple to complex, with the main goal of reducing cognitive load and increasing ease of use.
Note: Original definition might be something like: technique that sequences information and actions across several screens in order to reduce feelings of overwhelm for the user; but one can hopefully see how this generalizes outside of the original field.
A system designed 'using' PDC should allow beginners to use the (core of the) system without feeling frustrated, and allow powerusers to accomplish advanced goals.
The principle is used outside the UI/UX field, notably in the field of the programming-language theory (this is the context of PDC the rest of the article is concerned about). In this context, the aforementioned interface is the language itself - and not just the syntax but semantics as well.
A closer look
Since PDC is a 'general' principle, there is no single way to implement it or use it, but there are some things one should follow, most notably:
Simple things should be simple and complex things should be possibleLet's have a look at a traditional example -
Hello world!
program.
class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}
So in order to see text "Hello world!" on the screen, you need to learn (to some degree):
- What are classes?
- What is
public
? (Is there aprivate
too? What else is there for that context?) - What are static functions?
- What are functions, and how do we call them?
- How to accept command line arguments? And also, what is the syntax for arrays?
- There is 'module' system, and there is System module (or is it a library after all?)
- How to compile and run this program?
Compare that with the Python alternative:
print("Hello world!")
This seems a more reasonable solution...
Now, on the complex things being possible, it is crucial to remember that each stop along the complexity axis is incremental. It is not enough for 'hello world' to be simple if something like reading input requires understanding some obscure part of the language. Let's try that, again, both with Java and Python. Now here is the goal: ask user for the name, let them enter the name, and then greet them.
name = input("Hi, what is your name?\n")
print("Hello "+ name + "!")
Let's see what is new:
- How to create variables. (
name = ...
) - How to take user input. (
input(...)
) - In print function, there are some special character that represents a newline. (
"\n"
)
In reality, we could've offered an even simpler example (e.g. we could've avoided a newline character introduction), but from my experience in teaching Python to beginners, this is completely understandable. Now let's look at the Java alternative:
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Hi, what is your name?");
String name = scanner.nextLine();
Greeter greeter = new Greeter(name);
greeter.greet();
}
}
class Greeter {
private String name;
public Greeter(String name) {
this.name = name;
}
public void greet() {
System.out.println("Hello "+ this.name);
}
}
What even is going on here??
- Another library, this time
Scanner
presumably for 'scanning' user input. - How to create classes.
- How to create a class constructor, and what even is constructor.
- How to create methods.
- How to create class fields/properties.
- How to instantiate a new class?
- Aha, now there is also a
System.in
. - How to define a variable.
- How to call methods on objects.
- If you by accident make
Greeter
class public, you will receive an error indicating that the solution is to create another file for that class. - Also, we've used a
Greeter
before we defined it, so forward references are supported.
Note: Readers experienced with Java might complain that this example is crafted in a bad faith, after all, there was no real reason for us to define a whole new class
Greeter
. But I'll let you know that this example is modified (as in
simplified) version of the top result of the search 'java greeter'. It is not untrue to say that this is a culture in Java.
Conclusion
Following the PDC does not mean that the system is well designed - there are other aspects to a language other than 'being easy to use for beginners'. But, given how many resources we, as a society, invest in teaching programming and how important the goal is, it would probably be wise to spend some resources on thinking how we can make it easier for people to really grok the subject.
Additionally, signs of poor PDC show themselves in other places where affected group is not just 'beginners' but more advanced users. PDC is not just a design principle, not just a teaching aid - it is a philosophy that can make powerful systems more humane.
The field of PLT is not solved. Demand is huuuuugeeeee. We should do better. We deserve better.
This is it for today. I hope you find this article useful. As per usual, if you find any errors, send me a
mail at
luka [at] ljudi [dot] org
. Cheers!