
A principled approach to system design and programming - yosoyubik
https://urbit.org/blog/precepts/
======
r1b
Urbit is a cool idea and I resonate with its motivation but I fundamentally
disagree with its execution.

The fact that we have bad platforms does not imply that we have bad systems or
bad protocols. I think the rotten core of the bad-ness of the internet is
commercial infrastructure. It's prohibitively expensive for users to truly own
the most basic commodities of internet infrastructure, i.e names (DNS),
numbers (IP) and peers (BGP). These commodities would enable users to make the
most of the protocols that we already have.

There are already many projects that try to combat the commercialization of
the internet by adding new systems and protocols (Solid, IPFS and ActivityPub
come to mind). Users shouldn't only be free within the confines of these
systems - they should be first class nodes on THE network.

The spirit of Urbit is spot on but it's at the wrong layer of the OSI model. I
have much more faith in people who are trying to operate public networks (i.e
NYCMesh) and would like to see more projects that aim to de-centralize the
basic commodities of the internet.

~~~
eklavya
Is it economically viable to have all this infrastructure without commercial
interests?

~~~
RodgerTheGreat
Much of the physical and logical infrastructure was heavily subsidized or
outright paid for with public funds. One could argue that it was _never_
economically viable, but forced to appear that way.

Internet infrastructure is not unique in this respect.

The idea that markets optimizing for profitability naturally tackle hard
problems requiring immense up-front costs is an attractive lie.

~~~
eklavya
And so is the idea that public or government can maintain a good quality infra
(at scale, everything works in a small community). At least where I live the
public company provides the worst possible services and all improvement has
come from the private sector competition.

~~~
untoreh
thats why usually the best approach is public owned and private leased..

------
toolslive
> Everything should be CQRS.

For systems, this is going to be painful: you want to be able to do things
like "compare-and-swap" which are already an action and a query bundled in
one. You need this for 2 reasons:

    
    
       - consistency: you want the query and the update to be done in one go. atomically
       - performance: doing it like this is faster as 
         you're combining 2 things in one call, iso 2.

~~~
rwhaling
That was my immediate thought as well - CQRS doesn't fit well with the
"everything should be deterministic" principle, unless they have a very
different definition of CQRS than what is in common use.

In theory, it is possible to do "synchronous CQRS", where the update to your
write-side is done in a single transaction with the update to the read-side,
but that's not how I've ever done it in my (Scala/Postgres based) CQRS app
experience.

~~~
parsnips
Compare and Swap is a command. E.g. Optimistic Concurrency.

------
sk5t
> For example, the conventional name for a variable of type path is pax. You
> should have a good reason for using any other name for a path.

Ah yes, let's appropriate the Latin word for "peace" and demand everyone use
it for paths.

An utterly fanciful take, this. Must be nice to have the time to cultivate and
commemorate such a detailed set of principles.

~~~
wrycoder
I missed that this was urbit, but as soon as I read your post, I said hm,
urbit?

------
mnem
It’s quite difficult to tell if this is genuine or satire. I really hope it’s
the latter though.

------
crimsonalucard
>The Law of Leaky Abstractions is a lie; abstract airtightly.

Man, when I read things like this about "design principles" I know I'm getting
into a bag of hand wavy opinions with no rigid theoretical proofs. That's fine
because not everything is covered. But the minute you say something that is
outright false I know you're worthless.

All abstractions leak. I cannot make an abstraction perform better than what's
underneath. The performance leaks through every single time. An abstraction
will always only be worse performing then what's underneath simply due to the
cost overhead of the abstraction itself.

Rust is a great example. It has something called zero cost abstractions,
meaning that the abstractions that Rust uses are more complicated than normal
in order to maintain the zero performance cost. That is leakage. There is
always a cost.

~~~
naasking
> All abstractions leak. I cannot make an abstraction perform better than
> what's underneath

Performance is not within the scope of abstraction. This is a category error.

Also, your claim is incorrect as a general statement. The type structure of a
given program is an abstraction of its value flow, but without that
abstraction a compiler would not be able to optimize it nearly as well. A
typed program will always be faster than an equivalent untyped program.

Creating an abstraction may also allow you to add a transparent memoization
layer, which not only can make your program orders of magnitude faster, it can
make previously unsolvable problems solvable (see how PEGs handle left
recursion).

~~~
AnimalMuppet
> > All abstractions leak. I cannot make an abstraction perform better than
> what's underneath

> Performance is not within the scope of abstraction. This is a category
> error.

It's not within the scope of abstraction... until it is. When that beautiful
abstraction does exactly what you need, but does it too slowly to be usable in
your circumstances, performance is not separable from the abstraction. (I
mean, yes, performance is part of the _implementation_ of the abstraction, not
the abstraction itself. But the moment I have to care about the implementation
of an abstraction rather than the abstraction itself, the abstraction has
leaked. Performance is absolutely one of the ways that this can happen.)

And, as a concrete example, the STL went to great lengths to specify the
_performance_ of their abstractions.

~~~
naasking
> But the moment I have to care about the implementation of an abstraction
> rather than the abstraction itself, the abstraction has leaked.

No, that's not what leaky abstraction means. If an abstraction specifies its
performance properties, but those properties depend on context that _isn 't
captured by or enforced by the abstraction_, that's a leak.

To use your example of the STL, if you can allocate a fast constant-time
abstraction at a misaligned address, thus causing it to violate its own
performance specification, that's a leaky abstraction.

Having the wrong performance characteristics simply means it's the wrong
abstraction, not that the abstraction is leaky.

~~~
AnimalMuppet
I think you're a bit too narrow in your definition. If an abstraction
specifies properties, but I have to care about more than those properties to
be able to use the abstraction, then the abstraction leaked.

Performance can be one of those things I have to care about.

------
flyinglizard
This entire Urbit thing has the vibe of a Boards of Canada music video. I love
it even if I don't quite understand it (which I bet no one does, including
their investors).

------
BubRoss
I agree with some of this on some level, but this article is a big list of
extremely abstract concepts that it doesn't explain how to achieve. It
definitely doesn't explain how to achieve them in a practical way in general
programs with minimal hits to speed and latency, etc. etc. It's like someone
saying 'keep it simple stupid'. Great, tell me how to simplify.

~~~
scythmic_waves
IKR?

> (Almost) Everything should be pubsub?

Gee thanks, I'll just go make everything pubsub. Except the things I
shouldn't. The distinction will be clear I'm sure.

I'm not saying I disagree with all their points. But without examples it's not
clear what they even mean, let alone how to apply them.

------
keyle
Completely unrelated but I fell in love with the image compression, black and
white + high dither.

~~~
chubot
Similar aesthetic:
[https://solar.lowtechmagazine.com/about.html](https://solar.lowtechmagazine.com/about.html)

~~~
mprovost
Cool it looks like they're using a plugin based on
[https://github.com/hbldh/hitherdither](https://github.com/hbldh/hitherdither)
to do the dithering

------
yosoyubik
Discussion: [https://urbit.org/blog/precepts-
discussion/](https://urbit.org/blog/precepts-discussion/)

~~~
sk5t
But, this is not discussion at all--it's a doubling-down on various points of
the manifesto. "Maybe you didn't catch my subtly brilliant note about tab
spacing; now read a further two paragraphs of microdosed wisdom on the matter
and you may become enlightened."

------
naasking
Not sure some of these precepts are possible:

> A.2 Everything should be CQRS.

Some things require strong consistency, even at the UI level. Eventual
consistency is probably the right default though. Unfortunately, we still
don't have good abstractions at the language level to manage this.

> A.4 A subscriber shouldn't affect a publisher.

Literally impossible. Either a subscriber is polling the publisher, or the
subscriber registers with the publisher to receive updates. Either way, the
subscriber is inducing state transitions in the publisher. What other possible
meaning can be assigned to "affect" in order to make this precept valid?

> D.1 Academia has many genuinely smart and interesting ideas, but always
> remember that pursuing them whole-heartedly will never result in a useful
> product.

Yeah, not at all sure that's correct. Lots of academic research is funded by
commercial interests. In fact, currently one of the biggest corporations in
the world at this time (Google) started as academic research.

> D.2 Those people (academics) wasted a lot of time finding the right answer,
> but now that they've done it, you must exploit it.

 _Spent_ a lot of time. "Wasted" implies there was a better way.

> D.5 Practice tells you that things are good or bad; theory tells you why.
> Never use theory to design a good system from scratch; only practice can
> tell whether the system is good.

I don't think this is coherent. If theory tells you why a system is bad, then
that immediately entails what a good system should look like.

What I think typically happens, is that a system designed by theory is so good
at solving the problems it was designed for, that it's then applied to
similar-but-not-quite-the-same-problems, and thus it becomes inadequate again.

~~~
AnimalMuppet
A.4: I think you're a bit too literal here. A subscriber shouldn't affect the
publisher other than by subscribing, and by the tiny bit of time it takes to
be called.

Why those two exceptions? Because those two exceptions are mandatory in the
publish/subscribe model. You can't escape them and do publish/subscribe. But
the claim is, a subscriber shouldn't do anything beyond that, and that is
actually a useful and important claim.

A subscriber shouldn't send data back to the publisher via the return value of
a subscribed message, still less via reference parameters. A subscriber
shouldn't affect the publisher's performance by taking too long to handle one
of the messages. There may be other ways as well.

D.5: There's a difference between theory and practice. If the system is good
in theory but bad in practice, then theory will not tell you so. Only practice
can tell you.

You can, based on that practice, create an improved theory. That theory will
tell you what a good system should look like... in theory. In practice, such a
system may still be bad, just in a different way from the previous system.
Again, you need practice to tell you this, not theory.

------
ainiriand
I've found this list quite dogmatic. I would like to see them wrestle with the
business side of my company at the meetings.

------
z0mbie42
42: Use typed and safe languages

[https://github.com/urbit](https://github.com/urbit)

------
praptak
This is a set of very strong and detailed opinions about design. Do they have
any street cred to back it up?

------
anton_gogolev
> The Law of Leaky Abstractions is a lie; abstract airtightly

This one... Our entire computing world is a pie of terrible abstractions held
together by duct-tape and billions of man-hours spent working fixing those
leaks.

~~~
AnimalMuppet
This one is wrong. The Law of Leaky Abstractions is in fact _not_ a lie. All
abstractions actually do leak.

People take that as an excuse to be sloppy, which it isn't. You should do the
best you can to make non-leaky abstractions. When you have done so, you should
look for the leaks, and do your best to plug them. After that, you should do
so again. You should _really try_ to make it as solid as you can.

But it will still leak. It will be less garbage than much of what we have to
build on, because of the effort you put into making it better. But it will
still leak.

------
linpengcheng
1\. Too many principles equals no principles, for example: Don't exceed 10
principles.

2\. Simplicity and Unity must be parallel. Pure piping systems meet this
principle.

3\. Principle should be specific and executable.

4\. Principle should not affect flexibility.

5\. Principle should be consistent with mainstream modern industrial
production principles.

[https://github.com/linpengcheng/PurefunctionPipelineDataflow](https://github.com/linpengcheng/PurefunctionPipelineDataflow)

~~~
naasking
Your list is inconsistent. Principles necessarily constrain flexibility. For
instance, principle 5 means I can't create a system that isn't consistent with
mainstream modern industrial production principles.

------
sriku
Loved the language - "Each timeless data structure is a brick in the
foundation of digital civilization."

------
andrekandre
> Deterministic beats heuristic.

> Heuristics are evil and should only be used where determinism is infeasible,
> such as in cache reclamation

are these two things really in conflict? they seem orthogonal, but maybe i’m
missing something...

~~~
virgilp
Yes that's most likely a misunderstanding there - most heuristics I've used
were very much deterministic. Non-determinism is evil, that I would agree -
but heuristics aren't. As long as you understand they are heuristics and might
fail/lead to suboptimal results.

~~~
naasking
Most internet APIs use timeouts. That's as nondeterministic as it comes.

~~~
marcosdumay
Networks are non-deterministic by nature... Just like disk IO, but on networks
it's in an entirely new level.

~~~
virgilp
Which is why the first rule of distributed systems is "don't distribute your
system"

------
TrueDuality
The article mentions a `duct` abstraction several times but I've never heard
of this nor been able to find anything relevant through some searching. Does
someone have some insights on it?

~~~
yosoyubik
From the discussion [1]: "A duct is akin to a first-class call stack".

For a more detailed explanation, you can look up the type definition [2] in
Arvo (Urbit's Kernel) and here [3] you can find an example of how the stack
looks when setting up a timer.

[1] [https://urbit.org/blog/precepts-
discussion/](https://urbit.org/blog/precepts-discussion/)

[2]
[https://urbit.org/docs/tutorials/arvo/arvo/#duct](https://urbit.org/docs/tutorials/arvo/arvo/#duct)

[3] [https://urbit.org/docs/tutorials/arvo/move-
trace/](https://urbit.org/docs/tutorials/arvo/move-trace/)

------
loopz
The lengths devs go to become priests..

~~~
omarchowdhury
Do you mean in terms of taking extra discipline on themselves (which might
seem unnecessary to outsiders), or in terms of preaching what they think is
right?

~~~
fatbird
I think he means in terms of defining and controlling orthodoxy.

