Skip to content

Commit 99b5d91

Browse files
authored
Merge pull request #12 from yahoo/sal/newdocs
update readme and publish new changes to npm
2 parents 0da8d1c + b2698b9 commit 99b5d91

File tree

2 files changed

+158
-54
lines changed

2 files changed

+158
-54
lines changed

README.md

Lines changed: 154 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,176 @@
1-
Behavior Graph is a software architecture and state management library. It greatly enhances your ability to write complex user facing software and control systems. Broadly speaking, it belongs to the category of libraries which includes Redux, MobX, Rx (Reactive Extensions), and XState. It works by providing a specialized unit of composition which we call the __behavior__. Behaviors are simple blocks of code together with their dependency relationships.
1+
Behavior Graph lets you build your program out of small, easily understood pieces in a way that lets the computer do more of the work for you.
22

3-
## [Please See the full Documentation Site](https://yahoo.github.io/bgdocs/docs/typescript)
3+
It is an architecture and supporting library that simplifies the type of complexity that comes with event-driven software such as user facing applications and control systems.
44

5-
## Is it any good?
5+
It's also a fun way to program.
66

7-
Yes
7+
## Who's it for?
88

9-
## Highlights
9+
It is particularly helpful for developers building:
1010

11-
* Minimal boilerplate
12-
* Scales from the simple to the very complex
13-
* Incremental adoption: works alongside existing code and frameworks
14-
* Handles state, events, and effects all in one
15-
* Multi-platform (Javascript/Typescript, Kotlin, Objective-C, Swift)
16-
17-
We developed Behavior Graph to address our own complexity challenges while building an iOS video playing library which is used internally throughout the suite of native Yahoo mobile apps. After years of development and production usage, it has proven to be incredibly competent at scale. We have since ported it to multiple languages including Javascript/Typescript. It is less than 1500 lines of code and contains no external dependencies.
11+
* Web app front ends
12+
* Mobile and desktop applications
13+
* Control systems
14+
* Robots
1815

19-
Behavior Graph will particularly appeal to anyone with a willingness to rethink how we write software applications.
16+
We originally developed it for ourselves to use in a video playing library at Yahoo. Even though we had experienced engineers and excellent test coverage, we still struggled with the complexity of the codebase. Behavior Graph is our solution.
2017

21-
## What does it look like?
18+
Or maybe you're the type of person who likes nerdy new software ideas. (Seriously though, who doesn't, amirite?) We guarantee you will find Behavior Graph interesting.
2219

23-
The below block of code implements a simple counter using Behavior Graph.
24-
It can increment the counter or reset it back to zero.
20+
## How does it Work?
2521

26-
About 70% of the concepts you need to work with Behavior Graph are contained in this one example.
22+
As programmers it is natural to partition our software into smaller tasks. Consider a typical Login form.
23+
1. When a user clicks on the Login button, we want to validate the Email and Password fields.
24+
2. If validation passes we want to make a network call to log the user in.
25+
3. And we want to update the UI to provide feedback in case the validation fails, or disable the login button while we are actively logging in.
26+
27+
Most programming languages offer __functions__ as the primary tool for creating these subtasks. The code for our Login form will have `validateFields`, `networkLogin`, and `updateUI` functions. There will also be an `onLoginClick` function that looks like this:
2728

28-
<!-- Intro-1 -->
2929
```javascript
30-
this.increment = this.moment();
31-
this.reset = this.moment();
32-
this.counter = this.state(0);
33-
34-
this.behavior()
35-
.demands(this.increment, this.reset)
36-
.supplies(this.counter)
37-
.runs(() => {
38-
if (this.increment.justUpdated) {
39-
this.counter.update(this.counter.value + 1);
40-
} else if (this.reset.justUpdated) {
41-
this.counter.update(0);
42-
}
43-
});
30+
function onLoginClick() {
31+
validateFields();
32+
networkLogin();
33+
updateUI();
34+
}
4435
```
4536

46-
A typical Behavior Graph program consists of dozens or hundreds of behaviors like this, each with its own responsibilities.
47-
The Behavior Graph library then ensures these behaviors are correctly specified and runs them at the correct time and in the correct order.
48-
At scale this is shockingly effective.
37+
These functions are not independent, however. There are __dependency relationships__ between them that need to be respected.
38+
* `validateFields` depends on `onLoginClick` being run.
39+
* `networkLogin` depends on `onLoginClick` being run, and it depends on the results of `validateFields`.
40+
* `updateUI` depends on the results of both `validateFields` and `networkLogin`.
4941

50-
## Is it for me?
42+
__Functions__ cannot express dependency relationships directly. Instead we must call functions in a particular order to uphold these relationships.
43+
If we call `networkLogin()` before `validateFields()` the feature won't work. It has to be after. `networkLogin` depends on the validation in `validateFields` succeeding.
44+
45+
We could partially encode the dependency relationships by using parameters and return values (aka functional programming). This gives us additional structure, but it doesn't remove the need to call these functions in a correct order. Calling something like `networkLogin(validateFields())` is still a sequence of function calls. It's just sideways.
5146

52-
Behavior Graph is a general purpose library which you can use to organize the event driven logic in any program.
53-
It should also be of interest to anyone with an interest in software engineering and architectures.
47+
The problem is that expressing dependency relationships in terms of sequenced function calls means work for the developer:
48+
* There's work to get it correct.
49+
* There's work to rearrange calls as dependencies (inevitably) change.
50+
* There's work mentally translating back from sequenced function calls to the original dependency relationships in order to understand the intent of the code.
51+
* And there's work fixing errors whenever any of these efforts go wrong.
5452

55-
Specifically if you are working on any of these categories, you should definitely consider it:
53+
But maybe all this work isn't necessary. What if functions _could_ express dependency relationships?
5654

57-
* Web apps
58-
* Mobile apps
59-
* Desktop Applications
60-
* User Interfaces
61-
* Control Systems
62-
* Robots
63-
* Games
55+
__Behavior Graph__ is a library that provides this alternative. It introduces a new unit of code organization called the __behavior__. It is a block of code together with its dependency relationships.
56+
57+
Unlike functions, behaviors are never called directly. Instead, behaviors declare their interfaces using reactive containers of data called __resources__. When data in these resources changes, Behavior Graph knows that any dependent behaviors need to run. Behaviors together with resources form a graph. (A graph of behaviors! Get it?!)
58+
59+
This gives us:
60+
1. _Control flow for free_: The computer uses the dependency relationships to run our behaviors in the correct sequence. This works just like spreadsheet formulas.
61+
2. _Ease of maintenance_: Requirements inevitably change, and do dependencies. Control flow automatically adapts.
62+
3. _Legibility_: Dependency relationships are explicit. We can look at a behavior and immediately see how it interfaces with other behaviors. This is unlike functions which are often linked via calls made in some other part(s) of the code.
63+
64+
Behavior Graph isn't a replacement for functions. (We wrote it with functions, hello!) Instead it gives us a higher level of abstraction for partitioning our code into subtasks. It lets us say "these two blocks of code are related and here's how". And with that information both humans and the computer are better able to infer the intent of the code.
65+
66+
## Can I see an example?
67+
68+
Behavior Graph introduces a handful of new concepts.
69+
These concepts aren't difficult, but you will require some orientation.
70+
71+
* We've created a [short walk-through of a Login form](https://yahoo.github.io/bgdocs/docs/typescript/code-example/) using Behavior Graph.
72+
* You can also take a look at [one of our tutorials](https://yahoo.github.io/bgdocs/docs/typescript/tutorials/tutorial-1/).
73+
74+
## Small
75+
76+
Behavior Graph is a small library. It's around 1500 lines of formatted code. It has no dependencies. The Javascript is less than 6KB minified + gzip'd.
77+
78+
## Incremental
79+
80+
It is easy to introduce into a codebase incrementally. It is designed to work side by side with existing code. We gradually migrated Yahoo's video playing library, while in production, as we became confident in Behavior Graph's feature set.
81+
82+
## Scale
83+
84+
A complex codebase is exactly where it brings the most benefit. Our team uses it daily in a codebase where the status quo wasn't good enough.
85+
86+
## Multiplatform
87+
88+
Behavior Graph has been ported to multiple platforms.
89+
90+
* Javascript/Typescript: [bgjs](https://github.com/yahoo/bgjs)
91+
* Objective-C: [bgobjc](https://github.com/yahoo/bgobjc)
92+
* Swift: [BGSwift](https://github.com/yahoo/BGSwift)
93+
* Kotlin/Android: [bgkotlin](https://github.com/yahoo/bgkotlin)
94+
95+
## Obtaining Behavior Graph
96+
97+
Javascript Behavior Graph is hosted on NPM @ [behavior-graph](https://www.npmjs.com/package/behavior-graph).
98+
99+
Behavior Graph is also available via a number of popular CDN Services. You may prefer to use these when importing directly into the browser or with Deno.
100+
101+
* [Skypack.dev](https://www.skypack.dev/view/behavior-graph)
102+
* [JSDelivr](https://www.jsdelivr.com/package/npm/behavior-graph)
103+
104+
## Documentation
64105

65-
## How to Get It
106+
[Go here for the full documentation site](https://yahoo.github.io/bgdocs/docs/typescript/tutorials/).
107+
108+
While there are only a handful of basic concepts in Behavior Graph, it does require a shift in thinking. We recommend you start with the [Getting Started guide](https://yahoo.github.io/bgdocs/docs/typescript/quickstart/) then work through the [Tutorials](https://yahoo.github.io/bgdocs/docs/typescript/tutorials/tutorial-1/).
109+
110+
## Contact Us
111+
112+
We really do like talking about Behavior Graph.
113+
Discord is a good place for that.
114+
115+
[Behavior Graph Discord](https://discord.gg/5mvat8tc7d)
116+
117+
## Contributing
118+
119+
* Yes there are many interesting areas for contribution. Please ask us.
120+
* Don't just make a pull request. We would prefer to let you know upfront if your idea is unlikely to be accepted.
121+
122+
## Comparisons
123+
124+
Behavior Graph builds on concepts from [reactive programming](https://en.wikipedia.org/wiki/Reactive_programming). It uses the same underlying idea to automate control flow by using existing dataflow dependencies.
125+
126+
However, programming with Behavior Graph feels different than when using other reactive programming libraries. It is not functional reactive programming. It is not built around streams. And it is not optimized for assembling observable chains of data transformations.
127+
128+
Behavior Graph is also not a reactive UI library. You should continue to use your preferred UI framework of choice.
129+
130+
Instead Behavior Graph gives developers a tool for organizing their software around dependency relationships. We consider the following features essential for this:
131+
132+
* __Bipartite Graph__: Behavior Graph separates reactive blocks of code, _behaviors_, from reactive containers of data, _resources_. Behaviors can update multiple resources independently. Their relationships can vary dynamically at runtime. They can exist in separate modules and with separate lifetimes.
133+
* __Imperative Friendly__: Many reactive libraries have a strong functional programming flavor. This can lead to added friction when working with non-reactive code. Behavior Graph is designed to be compatible with existing imperative code and APIs. The code inside behaviors is as imperative as you like. We provide ways to create side effects and mutate state. You are free to read the contents of resources from external code.
134+
* __Explicit__: Behaviors declare their relationships explicitly. This aids in navigation and readability in large codebases. Reading and writing reactive data does not look like normal variable access. Reactive variables are not the same as normal variables and we prefer presenting them that way.
135+
* __Error Detection__: By understanding the underlying graph, the computer is able to detect errors for us. Behavior Graph tells us when we have specified our dependencies incorrectly.
136+
* __Glitch Free__: Glitches occur when multiple dependency paths result in the same reactive code getting run twice. Behavior Graph does not have glitches.
137+
* __Transactional__: Side effects are always postponed until after all other reactive code has completed to ensure consistent state. Reactive events are serialized to prevent side effects from leaking new reactive events into the current event.
138+
* __A Language for Change__: We can ask a resource if it "just updated" and "what it updated from".
139+
* __Dynamic Graph__: Dependencies are dynamically updatable. Different parts of a running program which have different lifetimes can all be part of the same graph.
140+
141+
## Challenges
142+
143+
There's always trade-offs with any programming paradigm (even the one that ships with your preferred programming language). We have worked hard to keep Behavior Graph from forcing you into a corner. It is designed to be compatible with existing code.
144+
145+
Wherever you feel friction, just don't use it.
146+
147+
Here are some challenges based on our own experience using it daily:
148+
149+
* You need to learn it. As will people who work on the same code. Sorry, there's no way around this.
150+
* Not all problems are dependency problems. You will be surprised how much of your code can be effectively organized into behaviors. At the same time you will need to develop a sense of where it isn't needed.
151+
* Dependency cycles happen. They can be tricky. Behavior Graph lets you know where they are and offers some debugging tools to help visualize it. But it's still up to you to fix it. This requires leaning back in your chair and thinking.
152+
* Debugging is different. We've noticed that the first tool programmers reach for when they run into an error is the stack frame debugger. They want to figure out _why_ the current line of code is running. With Behavior Graph this information is no longer on the stack. Programmers need to learn to use the tools Behavior Graph provides for this. We think there's room for interesting innovation here.
153+
* It is a library. It's impossible to avoid seeing some of its internals inside stack traces and errors. We think there's room for interesting innovation here as well.
154+
* Performance. Behavior Graph is plenty fast, but it is doing some work for you. And some work takes more than zero time. If you are writing high performance code (ie nanosecond time-frame), we recommend you use the proper tools for the job.
155+
156+
## Going Deeper: Reactive Programming
157+
158+
If you search on the internet for "what is reactive programming" you are likely to end up more confused than before you searched. For us, the benefits are all about simplifying control flow. We can see this in spreadsheet formulas. They are an easy example of how reactive programming improves the user experience.
159+
160+
In spreadsheet software, a formula often depends on the contents of other cells. When the contents of those cells change, the formula that depends on them is rerun. The formula's cell then updates with the new results. This updated cell then causes any formulas that depend on it to rerun. This process cascades across the cells in the spreadsheet. Formulas run at the correct time because the computer has automated the control flow for us. It knows how to do this because the formulas already specify what other cells they depend on.
161+
162+
Now, let's imagine a different type of spreadsheet program. In this one, the program does _not automatically run_ formulas for us. Instead it requires us to do this manually. After we type in a formula for what a cell should display, we also need to type in which formulas should run whenever it updates. For example, if cells `B1` and `C1` depend on `A1`, then the formula for `A1` needs to explicitly tell them to run. This might look like this:
163+
164+
```excel
165+
A1 := 1 / 1000
166+
runFormulaFor(B1)
167+
runFormulaFor(C1)
168+
```
66169

67-
Behavior Graph is [available on NPM as `behavior-graph`](https://www.npmjs.com/package/behavior-graph).
170+
That's it. That's the feature. Would you switch to this new spreadsheet program?
68171

69-
See the [Quick Start page](https://yahoo.github.io/bgdocs/docs/typescript/quickstart/) for more ways to get started.
172+
No, because it's bad idea.
70173

71-
## Learning Behavior Graph
174+
Even if we get the control flow correct, every change we make comes with potential control flow errors. We need to mentally walk backwards and forwards along some implicit dependency graph to ensure that formulas are still running in the correct order. For example, what would happen if someone else comes along and changes the formula for `B1` so that it also depends on `C1`? The formula for `A1` becomes wrong because it's calls are in the wrong order. We need to run the formula for `C1` first. Maintaining a large spreadsheet like this would be madness.
72175

73-
While there are only a handful of basic concepts in Behavior Graph, it does require a shift in thinking.
74-
[Please See the full Documentation Site](https://yahoo.github.io/bgdocs/docs/typescript)
176+
But this is exactly what we do as programmers on a daily basis.

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "behavior-graph",
3-
"version": "1.0.0",
3+
"version": "1.0.1",
44
"main": "lib/cjs/index.js",
55
"module": "lib/mjs/index.js",
66
"types": "lib/mjs/index.d.ts",
@@ -18,7 +18,9 @@
1818
"redux",
1919
"state machine",
2020
"store",
21-
"effects"
21+
"effects",
22+
"reactive",
23+
"dataflow"
2224
],
2325
"license": "Apache-2.0",
2426
"devDependencies": {

0 commit comments

Comments
 (0)