Giter Site home page Giter Site logo

square / workflow Goto Github PK

View Code? Open in Web Editor NEW
1.1K 43.0 80.0 23.07 MB

A Swift and Kotlin library for making composable state machines, and UIs driven by those state machines.

Home Page: https://square.github.io/workflow

License: Apache License 2.0

Ruby 18.21% Shell 81.79%
reactive ui state-machine kotlin android swift ios workflow

workflow's Introduction

Overview

GitHub license

Workflow is an application framework that provides architectural primitives.

Workflow is:

  • Written in and used for Kotlin and Swift
  • A unidirectional data flow library that uses immutable data within each Workflow. Data flows in a single direction from source to UI, and events in a single direction from the UI to the business logic.
  • A library that supports writing business logic and complex UI navigation logic as state machines, thereby enabling confident reasoning about state and validation of correctness.
  • Optimized for composability and scalability of features and screens.
  • Corresponding UI frameworks that bind Rendering data classes for “views” (including event callbacks) to Mobile UI frameworks for Android and iOS.
  • A corresponding testing framework that facilitates simple-to-write unit tests for all application business logic and helps ensure correctness.

Using Workflows in your project

Swift

See the square/workflow-swift repository.

Kotlin

See the square/workflow-kotlin repository.

Resources

Support & Contact

Workflow discussion happens in the Workflow Community slack. Use this open invitation.

Workflow maintainers also hang out in the #squarelibraries channel on the Kotlin Slack.

Releasing and Deploying

See RELEASING.md.

License

Copyright 2019 Square Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

workflow's People

Contributors

amorde avatar aquageek avatar armaxis avatar asthatrivedi avatar bencochran avatar charbgr avatar davidapgar avatar dependabot-preview[bot] avatar dependabot[bot] avatar dhavalshreyas avatar glureau-betclic avatar jrodbx avatar justindsn avatar kingreza avatar mbrubin56-square avatar merge-when-green[bot] avatar mongoose700 avatar paulofierro avatar pyricau avatar rbusarow avatar rjrjr avatar salvatoret avatar steve-the-edwards avatar timdonnelly avatar vgonda avatar vrallev avatar wugeorgeq avatar ychescale9 avatar zach-klippenstein avatar zradke avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

workflow's Issues

Deprecate EventSelectBuilder.onSuccess?

EventSelectBuilder.onSuccess(Single) is either a wart that people resort to when they wish their Rx code could do things that come for free from a kotlinx.coroutines.experimental.selects.select statement, or else a necessary escape hatch because we can't anticipate everything.

If we're sure it's a wart, we should instead make EventSelectBuilder those use cases more directly.

The specific problem case that prevents us from deprecating onSuccess today is this one from the rx2.Reactor kdoc. It could be handled by making EventSelectBuilder aware of WorkflowPool.

If you need to handle other events while the workflow is running, use
the [EventChannel] and a combination of onSuccess() and onEvent().
Remember to call [WorkflowPool.abandonDelegate] if you leave while
the nested workflow is still running!

   is Delegating -> events.select {
     onSuccess(workflows.nextDelegateReaction(state)) {
       when (it) {
         is EnterState -> EnterState(state.copy(delegateState = it.state))
         if FinishWith -> when (it.result) {
           is DoSomething -> EnterState(DoingSomething)
           is DoSomethingElse -> EnterState(DoingSomethingElse)
         }
       }
     }
     onEvent<Cancel> {
       workflows.abandonDelegate(state.id)
       EnterState(NeverMind)
     }
   }

Fix leaky dialog warning in sample

Our old friend wants attention. I'm hoping we can use a lifecycle observer instead of the usual hacks, once #50 lands and we move to AndroidX.

android.view.WindowLeaked: Activity com.squareup.sample.authgameapp.ShellActivity has leaked window DecorView@9920615[] that was originally added here
    at android.view.ViewRootImpl.<init>(ViewRootImpl.java:485)
    at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:346)
    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
    at android.app.Dialog.show(Dialog.java:330)
    at com.squareup.sample.authgameapp.ShellCoordinator.ensureDialog(ShellCoordinator.kt:95)
    at com.squareup.sample.authgameapp.ShellCoordinator.access$ensureDialog(ShellCoordinator.kt:41)
    at com.squareup.sample.authgameapp.ShellCoordinator$attach$1.accept(ShellCoordinator.kt:65)

Maybe want this too:

private val Context.activity: AppCompatActivity
  get() {
    var wrapper = this as ContextWrapper
    var activity: Activity? = null
    do {
      if (wrapper is Activity) {
        activity = wrapper
      } else {
        wrapper = wrapper.baseContext as ContextWrapper
      }
    } while (activity == null)
    return activity as AppCompatActivity
  }

rx2.Reactor needs kdoc

AC: rx2.Reactor is documented well enough that it can be used without reference to the base coroutine Reactor interface.

Cleanup ReactorWorkflow result implementation once we're on kotlin 1.3

There's a bug in pre-1.3 when using the broadcast coroutine builder with the Unconfined dispatcher and CONFLATED capacity.

The broadcast helper starts the coroutine lazily (because items send before the first subscriber are lost). When the consumer subscribes, there’s a race between starting the broadcast coroutine and the channel actually realizing it has a subscriber it should be sending values to. The start wins, and because both are using the unconfined dispatcher, the broadcast coroutine seems to finish before the subscription actually happens so the consumer only sees an empty, closed channel.

Pre-1.3, line 16 never gets hit. The same code works fine in 1.3.

fun main(args: Array<String>) {
    val producer = GlobalScope
        .broadcast(Unconfined, capacity = CONFLATED) {
            println("producer sending")
            send("hi")
            println("producer sent")
        }
        .apply { invokeOnClose { println("producer closed") } }

    GlobalScope.launch(Unconfined) {
        println("consumer started")
        val consumer = producer.openSubscription()
        println("consumer subscribed")
        consumer.consumeEach {
            // This line never gets hit on pre-1.3.
            println("consumer received: $it")
        }
        println("consumer finished")
    }
}

We can work around this for now, but that should be cleaned up once we're on 1.3.

Publish HTML kdocs for all artifacts

AC:

  • kdocs publicly visible in the style of Okio
  • RELEASE.md includes instructions for how to
  • probably use ghpages
  • separate docs for workflow, viewbuilder

Build MockLauncher for easier WorkflowPool testing

AC:

  • it's easy to test a ComposedReactor without having to create elaborate shims
  • ideally WorkflowPool remains a simple, concrete class, not open, not an interface

e.g.

val mockLauncher = MockLauncher(SomeRealReactor) 
workflowPool.register(mockLauncher)

// ...

mockLauncher.enterState("blah")
mockLauncher.finishWith("fnord)

Remember that SomeRealReactor.Companion implements WorkflowPool.Type, so we have all the info we need, w/o ever executing a real reactor

Create Workflow sample using command line

This is particularly important to demonstrate where the lines between core workflows and platform-and-UI-toolkit-specific concepts are. Text view models/screen data is likely to be a lot simpler than that for GUIs, since there's no concept of "screens".

Move to AndroidX

AC: See Summary

AndroidX is (will be? I lose track) the way to go, we need to catch up. Don't try to do this until we're at Support v28, though.

Is Reactor.doLaunch too opinionated about dispatchers?

Currently, it forces the Unconfined dispatcher. Reactors can override this by using something like withContext if they actually care. The reason for this is that most reactors shouldn't care about what dispatcher they're running on (if they do, they are probably performing side effects and that's a smell).

However, this is surprising behavior since no other coroutine functions explicitly ignore the dispatcher from the passed-in context. Additionally, withContext is optimized to effectively no-op when the context isn't actually different.

There are three paths forward:

  1. No change. Passed-in context is always ignored, onReact must use withContext if it cares (which it shouldn't). This is nice because the extra verbosity makes it more obvious that it's a smell, however since it's so surprising that the context's dispatcher is being ignored in the first place, this could be a footgun.
  2. doLaunch continues to use Unconfined internally, but invokes onReact on the passed-in dispatcher. This removes the surprise, but feels a little over-engineered. Not sure if it's actually important that internal doLaunch code runs on Unconfined.
  3. No special dispatcher handling. This is what most of the coroutine builders do, and probably makes the most sense until proven otherwise. Then the only question left is what the default dispatcher should be if none is passed in:
    1. EmptyCoroutineContext – Again the standard, but will default the dispatcher to Dispatchers.Default which is unnecessary (doLaunch isn't doing much work of its own).
    2. Unconfined – Reasonable default for glue code, but may be surprising for onReact.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.