Code Monkey home page Code Monkey logo

reframe's Introduction


REFRAME

A software framework for managing reactive dependencies in object-oriented (OO) applications

Table of Contents
  1. About The Project
  2. Getting Started
  3. Usage
  4. Roadmap
  5. Contributing
  6. License
  7. Contact
  8. Acknowledgments

About The Project

image

REFRAME is a software framework which can be used by application developers to manage reactive dependencies in object-oriented (OO) applications. In object-oriented (OO) applications, objects collaborate by invoking each other's behaviour and data, thus forming dependencies. Sometimes there is a need (or benefit) to express these dependencies as reactive, i.e. in a way that when one object changes its data or invokes a metode, its dependent objects automatically react and update their state or invoke their own methods. In practice, such dependencies are often found in event-driven systems, graphical user interfaces, animation, spreadsheet systems, embedded systems, etc.

When need arises to treat dependencies as reactive dependences in OO applications, developers usually end up developing their own ad-hoc solutions inspired by Observer (or similar) design pattern. Such solutions may be challenging to develop form scratch. However, more importantly, such solutions often do not live up to the challenge of handling large and complex dependency graphs that may form when combining sufficient number of reactive dependencies. Some of the issues that frequently arise: not performing updates that are necessary, performing updates that are not necessary, performing updates redundantly, causing glitches (temporary inconsistencies) due to incorrect update order, creating infinite loops due to circular dependences. These issues may heavily distort results we get from the underlying software, as well as its performance. In order to avoid creating their own solutions from scratch, developers can use REFRAME to: specify individual reactive dependencies, combine reactive dependencies into a dependency graph, perform update process (sequentially or in parallel), analyse constructed dependency graph, visualize constructed dependency graph.

Built With

  • C# .NET
  • Visual Studio 2019/2022 with DGML Editor installed
  • .NET Framework

Getting Started

This is an example of how you may give instructions on setting up your project locally. To get a local copy up and running follow these simple example steps.

Prerequisites

  • C# .NET
  • Visual Studio 2019/2022 with DGML Editor installed
  • .NET Framework

Installation

In order to use Reframe framework you need to obtain framework binary files (.dll and .exe files). This can be done either by downloading ready to use binaries from GitHub Release page (ReframeCore.zip and ReframeTools.zip files), or by cloning the project and building these files by yourself.

Use scenarios

Reframe framework consists of 12 .dll files and one .exe file. However, which of these files will be necessary to use depends on the use scenario.

Component Description
ReframeCore The core component of the framework which enables end-user application to construct dependency graphs and perform update process. It contains abstractions representing members of reactive node hierarchy, dependency graph, update, scheduler, reactor and other essential parts of the framework.
ReframeBaseExceptions Contains the definition of the root REFRAME exception which is inherited by specific exceptions in other components.
ReframeFluentAPI Contains classes with extension methods which allow us to use reactor in a declarative style.
IPCServer Contains interfaces and abstract classes with reusable part of the server side of inter-process communication.
ReframeServer Contains concrete classes with REFRAME-specific implementation of the server side of inter-process communication.
ReframeExporter Contains classes responsible for exporting dependency graph data and update process data in a form of XML content.
ReframeToolsGUI Contains graphical user interface classes and coordinates the rest of the components.
IPCClient Contains interfaces and abstract classes with reusable part of the client side of inter-process communication.
ReframeClient Contains concrete classes with REFRAME-specific implementation of the client side of inter-process communication.
ReframeAnalyzer Contains abstractions representing members of analysis graph and analysis node hierarchies, factories for creating graph and node objects, filter specifications, analysis and metrics implementations, and other parts related to graph and update analysis.
ReframeImporter Contains utility classes which interpret XML content fetched from end-user application.
ReframeVisualizer Contains interfaces and abstract classes with reusable and technology-independent part of the visualizer implementation.
VisualizerDGML Contains concrete classes implementing visualizer using DGML technology.

From the perspective of end-user (host) application, there are three main scenarios.

  1. Scenario - Core features

The first, and the most basic use scenario assumes using only two components from REFRAME, namely: ReframeCore.dll and ReframeBaseExceptions.dll. These are mandatory components which allow end-user application to access core features of REFRAME, i.e. to construct dependency graphs and perform update process.

image

In order to use the core features of REFRAME it is necessary to reference ReframeCore.dll and ReframeBaseExceptions.dll libraries in the project we want to use them in. In order to do that, we first need to obtain dll libraries. This can be done either by downloading ready-to-use binaries from GitHub Release page (ReframeCore.zip and ReframeTools.zip files), or by cloning the project and building these files by yourself. When we have required dll files, we need to reference them in our project. Dependening on our IDE of choice (e.g. Visual Studio, Visual Studio Code, Resharper, etc.) this process might be different. In case of Visual Studio we would need to right-click at our project in Solution explorer, choose Add Reference option, and then find the dll files we want to reference.

image

  1. Scenario - Core features + Fluent API

The second use scenario introduces optional ReframeFluentAPI.dll component, which (as its name imply) contains implementation of Fluent interface. This allows us to, in addition to traditional imperative style, also use alternative, more declarative approach when specifying individual reactive dependencies between nodes.

image

Extending the base use scenario with fluent API requires referencing one additional component - ReframeFluentAPI.dll. This is done exactly the same as with the first two dll files.

  1. Scenario - Core features + Fluent API + Reframe Tools

The third use scenario is only relevant if we want to use REFRAME tools. It allows us to setup inter-process communication between end-user application and REFRAME tools. By introducing IPCServer.dll, ReframeServer.dll and ReframeExporter.dll components, we can start the server in end-user application which will respond to requests from the Analyzer tool (client) and send dependency graph data. Since integration of server components into end-user application and starting the server is a trivial task, application developers can switch to and from this use scenario easily.

image

In addition to referencing required dll files, in order for Reframe Tools to exchange information with end-user application we need to start Reframe server in end-user application. This can be done by adding following lines of code in Program Main method or any other convenient point in code.

var server = new ReframePipeServer;
server.StartServer();

Usage

Example 1 - Creating and registering new reactor object

Creating new reactor object with identifier "default" and registering it in ReactorRegistry to be available for further use.

var reactor = ReactorRegistry.Instance.CreateReactor("default");

Example 2 - Geting existing "default" reactor object from registry

var reactor = ReactorRegistry.Instance.GetReactor("default");

Example 3 - Specifying reactive dependencies

image

Example 4 - Performing update process of entire graph

In order to perform update process of entire graph we need to fetch reactor object from registry and invoke PerformUpdate method.

var reactor = ReactorRegistry.Instance.CreateReactor("default");
reactor.PerformUpdate();

Example 5 - Performing update process as a result of triggering change in object's state

public int A
{
  get {return _a; }
  set
  {
    _a = value;
    reactor.Update(this);
  }
}

Example 6 - Performing update process asynchronously

var reactor = ReactorRegistry.Instance.GetReactor("default");
(reactor.Updater as Updater).Strategy = UpdateStrategy.Asynchronous;
await reactor.PerformUpdate();

Example 7 - Performing update process in parallel

var reactor = ReactorRegistry.Instance.GetReactor("default");
(reactor.Updater as Updater).Strategy = UpdateStrategy.Parallel;
await reactor.PerformUpdate();

Example 8 - Reporting the progress and status of the ongoing update process

Reactor exposes three events that can be used to report on the progress and status of update process. These events are: UpdateStarted, UpdateCompleted and UpdateFailed.

var reactor = ReactorRegistry.Instance.GetReactor("default");
reactor.UpdateStarted += Reactor_UpdateStarted;
reactor.UpdateCompleted += Reactor_UpdateCompleted;
reactor.UpdateFailed += Reactor_UpdateFailed;

...

private void Reactor_UpdateStarted(object sender, EventArgs e)
{
  var graph = (sender as IUpdater).Graph;
  MessageBox.Show($"Update process for graph {graph.Identifier} has started!");
}

private void Reactor_UpdateFailed(object sender, EventArgs e)
{
  var error = sender as UpdateError;
  var graph = error.Graph;
  var failedNode = error.FailedNode;
  MessageBox.Show($"There was and error in node {failedNode.Identifier} during update process for graph {graph.Identifier}!");
}

private void Reactor_UpdateCompleted(object sender, EventArgs e)
{
  RefreshGui();
}

Example 9 - Displaying list of reactors

After starting REFRAME Tools a graphical user interface appeares showing the list of registered reactors in end-user application. For each registered reactor a detailed data about its structure can be displayed.

image

Example 10 - Displaying the list of reactive nodes on a different levels of abstraction

After selecting registered reactor, available menu offers six levels at which reactive nodes can be shown, e.g. object-member level. List of nodes are then displayed in a table with data available at chosen level of abstraction.

image

Example 11 - Displaying the list of reactive nodes with respect to their role in dependency graph

After selecting registered reactor and a level of abstraction, it is possible to show only reactive nodes with particular role (filtering by role) in a dependency graph, e.g. source nodes.

image

Example 12 - Displaying the list of reactive nodes with associated with selected node

After any list of reactive nodes is displayed, and any reactive node is selected, it is possible to display reactive nodes which are in various ways associated with selected node (filtering by association).

image

Example 13 - Displaying information about last performed update process

After selecting registered reactor we can show information about the latest update process. Here we can see information about the overall update process, such as update status, cause, duration, error, etc. Also, we can see the list of all reactive nodes which participated in the update process. In addition to usual information about reactive nodes, for each node we can see the duration of update, as well as whether the update resulted in a value change.

image

Example 14 - Visualizing the list of reactive nodes

After displaying any list of reactive nodes we can visualize it in a form of DGML graph shown in Visual Studio’s DGML Viewer.

image

image

Contributing

If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement".

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

(back to top)

License

Distributed under the MIT License. See LICENSE.txt for more information.

Contact

Marko Mijač, email: mmijac [at] foi.hr
Project Link: https://github.com/MarkoMijac/REFRAME

(back to top)

reframe's People

Contributors

markomijac avatar pi-user-2014 avatar

Watchers

James Cloos avatar

reframe's Issues

Skipping update optimization

In case when triggered node has not changed its value, we should skip update process in order to optimize dependency handling. This only makes sense if the initial node is PropertyNode. In case of MethodNodes, we can not be sure about the state state involve, so this optimization is not aplicable here. Similar is with CollectionMethodNodes.
In case of CollectionPropertyNodes, if triggered child node exists as explicitely added PropertyNode, then optimization applies as with any other PropertyNode. However, if triggering child node is only virtually present, then this optimization is not possible. It would be possible if we would track state for each and every child object, but this would require child objects to be explicitely added as nodes.

Implement abstractions for defining basic reactive node

Implement classes and interfaces required to define individual reactive node. These abstractions should encapsulate at least the following:

  • reference to class member (property or method) reactive node represents,
  • reference to associated object,
  • update method (in case of property reactive node this invokes separate method, and in case of method reactive node this invokes the method itself).

Document design patterns used in a code

  • "Collecting parameter" design pattern (mentioned in book TDD by example) is used (Tansferobject)
  • "Constructor chaining" design patterns is used (mentioned in book Pro C# 7)

Enable reactive node's triggering

  • Enable PropertyNode triggering

  • Enable MethodNode triggering

  • Enable CollectionPropertyNode triggering

  • Enable CollectionMethodNode triggering

Enable parallel update process execution

Implement algorithm to determine the possibility to execute update process in parallel, i.e. to find nodes in update path that can be executed in parallel. This will probably be done using variant of Coffman-Graham algorithm which divides dependency graph into layers. Layers have to be updated in a sequencial order, but nodes inside layers can be updated in parallel.

If parallel execution is possible, and the user has requested it, than the parallel execution will be performed.

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.