Giter VIP home page Giter VIP logo

berndruecker / flowing-retail Goto Github PK

View Code? Open in Web Editor NEW
1.3K 113.0 463.0 38.35 MB

Sample application demonstrating an order fulfillment system decomposed into multiple independant components (e.g. microservices). Showing concrete implementation alternatives using e.g. Java, Spring Boot, Apache Kafka, Camunda, Zeebe, ...

License: Apache License 2.0

Java 89.89% HTML 4.29% JavaScript 1.43% Batchfile 3.55% Dockerfile 0.85%

flowing-retail's Introduction

Flowing Retail

This sample application demonstrates a simple order fulfillment system, decomposed into multiple independent components (like microservices).

The repository contains code for multiple implementation alternatives to allow a broad audience to understand the code and to compare alternatives. The table below lists these alternatives.

The example respects learnings from Domain Driven Design (DDD), Event Driven Architecture (EDA) and Microservices (µS) and is designed to give you hands-on access to these topics.

Note: The code was written in order to be explained. Hence, I favored simplified code or copy & paste over production-ready code with generic solutions. Don't consider the coding style best practice! It is purpose-written to be easily explainable code.

You can find more information on the concepts in the Practical Process Automation book with O'Reilly.

Flowing retail simulates a very easy order fulfillment system:

Events and Commands

Architecture and implementation alternatives

The most fundamental choice is to select the communication mechanism:

  • Apache Kafka as event bus (could be easily changed to messaging, e.g. RabbitMQ):
  • REST communication between Services.
    • This example also shows how to do stateful resilience patterns like stateful retries leveraging a workflow engine.
  • Zeebe broker doing work distribution.

After the communication mechanism, the next choice is the workflow engine:

  • Camunda 8 (aka Zeebe)

and the programming language:

  • Java

Storyline

Flowing retail simulates a very easy order fulfillment system. The business logic is separated into the services shown above (shown as a context map).

Long running services and orchestration

Some services are long running in nature - for example: the payment service asks customers to update expired credit cards. A workflow engine is used to persist and control these long running interactions.

Workflows live within service boundaries

Note that the state machine (or workflow engine in this case) is a library used within one service. If different services need a workflow engine they can run whatever engine they want. This way it is an autonomous team decision if they want to use a framework, and which one:

Events and Commands

Links and background reading

flowing-retail's People

Contributors

berndruecker avatar bones0 avatar dependabot[bot] avatar jwulf avatar megglos avatar robvdlv 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  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

flowing-retail's Issues

Big overhaul

  • Update to Camunda 8.x
  • Switch Spring Cloud Streams to normal KafkaListener (more robust and better compatibility with other Spring things)
  • Remove unmaintained parts of the code, this mostly means:
    • NodeJS examples
    • Camunda 7
    • K8S deployment files
  • Add Github Action to build artifacts and deploy on DockerHub
  • Update Choreography Example (use latest Optimize with Identity and Event Ingestion)

Build problem: wrong maven dependencies

Hi,
I'm trying to build this project but some problem with dependencies rised.

  1. Order and Payment modules use <camunda.version>7.7.3-ee</camunda.version> but this version doesn't exist in public repository
    I've solved problem changing version to
    <camunda.version>7.7.0</camunda.version>

  2. These modules use

<dependency>
			<groupId>com.camunda.consulting.webapp</groupId>
			<artifactId>camunda-webapp-customized-webjar</artifactId>
			<version>7.7.2</version>
			<scope>provided</scope>
		</dependency>

this dependecy include another dependency which not exists

<dependency>
      <groupId>org.camunda.bpm.webapp</groupId>
      <artifactId>camunda-webapp-ee-plugins</artifactId>
      <version>7.7.2-ee</version>
      <type>jar</type>
      <classifier>classes</classifier>
    </dependency>

I've solved this problem removing this dependency camunda-webapp-ee-plugins from pom

No such host is known (<Cluster Id>.zeebe.camunda.io)

Hello,
When trying to run this example: I got the following error :
Steps done:

  • application.properties in all microservices was updated with the right credentials obtained from Camunda Cloud console.
  • mvn -f checkout exec:java
    Error :
    "Failed to resolve name. status=Status{code=UNAVAILABLE, description=Unable to resolve host .."

@berndruecker , Thanks in advance for your help.

Can't find event handler for Payment RetrievePaymentCommand event

Hi there,
This application doesn't work. I can receive an Order "OrderPlacedEvent" after posting an Order via Checkout Service, however the Payment Service is never triggered.

I'm running:
-Local Zeebe (zeebe-broker-0.20.0);
-Local Kafka (kafka_2.12-2.2.0)
-Java 8

Thanks,
Marcus

Starting Microservice error occurred

If I execute this command: mvn -f checkout exec:java

I receive the following error:

[ERROR] Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.6.0:java (default-cli) on project flowing-retail-java-kafka-or-rabbit-spring-boot-camunda-checkout: The parameters 'mainClass' for goal org.codehaus.mojo:exec-maven-plugin:1.6.0:java are missing or invalid -> [Help 1] org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.6.0:java (default-cli) on project flowing-retail-java-kafka-or-rabbit-spring-boot-camunda-checkout: The parameters 'mainClass' for goal org.codehaus.mojo:exec-maven-plugin:1.6.0:java are missing or invalid at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:212) at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153) at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145) at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:116) at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:80) at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51) at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128) at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:307) at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:193) at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:106) at org.apache.maven.cli.MavenCli.execute(MavenCli.java:863) at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:288) at org.apache.maven.cli.MavenCli.main(MavenCli.java:199) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289) at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229) at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415) at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356) Caused by: org.apache.maven.plugin.PluginParameterException: The parameters 'mainClass' for goal org.codehaus.mojo:exec-maven-plugin:1.6.0:java are missing or invalid at org.apache.maven.plugin.internal.DefaultMavenPluginManager.populatePluginFields(DefaultMavenPluginManager.java:641) at org.apache.maven.plugin.internal.DefaultMavenPluginManager.getConfiguredMojo(DefaultMavenPluginManager.java:594) at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:121) at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:207) ... 20 more [ERROR] [ERROR] [ERROR] For more information about the errors and possible solutions, please read the following articles: [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/PluginParameterException

I forced fqn main class in order to start a microservice:

mvn -f checkout exec:java -Dexec.mainClass="io.flowing.retail.checkout.CheckoutApplication"

Thanks in advance

Luca

Add more todos to comment on simplicity

I want to add some Todos to explain that some code is kept simple for easy understanding. A lot of code could be more generic or more elegant - but I like it to be very easy to read in the first place and not make it as elegant as possible

Update to Camunda Cloud

  • Update to latest Zeebe 1.x in prep for Camunda Cloud launch
  • Use Spring Zeebe in Java
  • Update readmes to describe Camunda Cloud (instead of self-managed Zeebe)

Error When starting Order and Payement

Noticed an error while starting thw two apps (individually they work)

Might be some shared lock on files ? same db ?

org.apache.commons.dbcp.SQLNestedException: Cannot create PoolableConnectionFactory (Database may be already in use: null. Possible solutions: close all other connection(s); use the server mode [90020-196])
at org.apache.commons.dbcp.BasicDataSource.createPoolableConnectionFactory(BasicDataSource.java:1549)
at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:1388)
at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)

Problem with Jersey on Order Camunda microservice

Hello,
I've tried to start the Order Camunda microservice with mvn -f order-camunda exec:java but I've got the following error :

[ERROR] Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.6.0:java (default-cli) on project flowing-retail-kafka-order-camunda: An exception occured while executing the Java class. Error processing condition on org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat: Failed to introspect Class [org.camunda.bpm.spring.boot.starter.rest.CamundaBpmRestJerseyAutoConfiguration] from ClassLoader [java.net.URLClassLoader@6e5c9a5d]: javax/ws/rs/core/Configurable: javax.ws.rs.core.Configurable

I needed to add the Jersey librairie dependancy in pom.xml with :

javax.ws.rs
javax.ws.rs-api
2.1.1


org.glassfish.jersey.core
jersey-common
2.28

search zeebe create instance command

Hi,

I search zbctl complete create instance command
I hve tried without succes
\zbctl.exe create instance order-zeebe --variables "{"orderId": "1234", "orderValue":99}"

Regards

add order-zeebe.bpmn to zeebe broker failed

Hi,

I have just started zeebe and i tried to add BPMN comming from project
C:\Users\windows\zeebe-distribution-0.17.0\zeebe-broker-0.17.0\bin\broker.bat OK
C:\Users\zeebe-distribution-0.17.0\zeebe-broker-0.17.0\bin\zbctl deploy C:\Users\tIdeaProjects\zeebejava\order\src\main\resources\order-zeebe.bpmn

15:40:33.721 [io.zeebe.gateway.impl.broker.cluster.BrokerTopologyManagerImpl] [gateway-zb-actors-0] INFO io.zeebe.transport.endpoint - Registering endpoint for node '0' with address '0.0.0.0:26501' on transport 'broker-client-internal'
juin 07, 2019 3:40:57 PM io.grpc.netty.NettyServerTransport notifyTerminated
INFOS: Transport failed
java.io.IOException: Une connexion existante a d¹ Ûtre fermÚe par lÆh¶te distant
at sun.nio.ch.SocketDispatcher.read0(Native Method)
at sun.nio.ch.SocketDispatcher.read(Unknown Source)
at sun.nio.ch.IOUtil.readIntoNativeBuffer(Unknown Source)
at sun.nio.ch.IOUtil.read(Unknown Source)
at sun.nio.ch.SocketChannelImpl.read(Unknown Source)
at io.netty.buffer.PooledUnsafeDirectByteBuf.setBytes(PooledUnsafeDirectByteBuf.java:288)
at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:1125)
at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:347)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:148)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:677)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:612)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:529)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:491)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:905)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Unknown Source)
I use java8

Regards

Kafka dies during docker startup on Windows

When starting up everything via Docker on Windows I experienced problems.

Somehow the Kafka docker container gets unresponsive:

C:\Users\ruecker>docker exec -i -t kafka_kafka_1 /bin/bash
Error response from daemon: Container 1bd116be6408531af7bb323e8f64890ed30d192366d092032c79f19565fa8a9a is not running

This leads to some services to timeout on startup:
inventory_1 | Caused by: org.I0Itec.zkclient.exception.ZkTimeoutException: Unable to connect to zookeeper server within timeout: 10000

After some time sometimes Kafka heals, but I also had to restart docker completely.

It does not happen if I remove two services (e.g. inventory & shipping) though.

question: idiomatic to use one topic?

hello,

i'm quite new to camunda and bpmn, so please for please forgive if this sounds stupid. is it idiomatic, recommended, or even necessary to have one (kafka) topic for all the messages flowing through the system? i'm hoping that this show-case repo uses only one in order to keep the complexity low. but i would expect dedicated topics between the stages.

one topic for all doesn't seem to me be good option from a scalability and performance perspective. having each listening party on the event-bus to read, evaluate, and optionally discard a message is costly. the more stages, the more event-/command-messages there will be, and the more events each component/listener needs to consume/process.

at least this is how i explain, why i can see a big difference in processing time of each order when placing 1 order vs 1000 orders at a time. (admitted, the later use-case is not frequent, but can regularly arise when the "order" application would have a temporary outage for some time and would need to catch up after being brought up again.)

i've extended the code a little bit by measuring the duration of the examples individual stages: https://github.com/xitep/flowing-retail/commits/pete/customization

i'm based on a few commits behind your current master but there were no significant changes i believe. you can run the applications via mvn -f <app> exec:java, follow the "order" application's log to see the timings per order and then place for example 1000 orders using curl:

curl -X PUT 'http://localhost:8090/api/cart/order-many?customerId=123&numOrders=1000'

maybe i'm misinterpreting something, but i appears that payment, fetching and shipping goods get more costly the more orders there are in the pipeline which i would not expect.

many thanks for clarifications in advance.

Maven issue

When i run mvn install as described in the readme i get the following

Downloading: https://app.camunda.com/nexus/content/groups/public/org/camunda/camunda-release-parent/2.5/camunda-release-parent-2.5.pom
Downloaded: https://app.camunda.com/nexus/content/groups/public/org/camunda/camunda-release-parent/2.5/camunda-release-parent-2.5.pom (13 KB at 108.2 KB/sec)
[ERROR] [ERROR] Some problems were encountered while processing the POMs:
[ERROR] Non-resolvable import POM: Could not find artifact org.camunda.bpm:camunda-bom:pom:7.7.3-ee in camunda-bpm-nexus (https://app.camunda.com/nexus/content/groups/public) @ line 20, column 16
@
[ERROR] The build could not read 1 project -> [Help 1]
[ERROR]

Thanks

Extend REST examples to also contain multiple service

Currently REST is only reduced to (payment -> credit card) which does not fit in the overall story of flowing-retail. Ideally, this example should also show order fulfillment, Shipment & Inventory and let them communicate via P2P REST.

Provide proper Windows CMD files

As an alternative to docker / docker-compose I still run this app locally often - so I want to provide the proper batch files for this in a re-usable manner

Kafka Docker Example Performance

Great Tutorial and Use Case. This shows clearly the benefit of a distributed workflow engine.

While testing the performance in the local setup, I noticed that the system is already at a limit with 10 orders per second. Clearly in a production environment, services would be distributed across separate VMs, and possibly also scaled horizontally for fault tolerance. Still it seems like there is a clear bottleneck in the Zeebe service writing data to ElasticSearch, and one would expect a performance of more than 10 workflows / second even in a sample setup. While all other services have done their job, the logs of Zeebe still show write requests to Elastic.

image

This results in Camunda Operate showing out of date information when it comes to the state of the workflow instances:

image

Wouldn't it be possible to batch the writes from Zeebe to ElasticSearch to improve the performance by quite a bit? Or Is batching already taking place? Why are the writes so slow?

retire zeebe-track

Retire zeebe-track as the story can be easily replaced with "Process Events Monitoring" capabilities that we will have in Camunda Optimize pretty soon (https://youtu.be/JptEJZ10Ra4). And the current config is pretty outdated

docker-compose for zeebe-track does not start fully (mongo error)

steps to reproduce
navigate to runner/docker-compose/docker-compose-kafka-java-choreography-zeebe-track.yml
run docker-compose -f docker-compose-kafka-java-choreography-zeebe-track.yml up

behavior
two services don't start because of exceptions
docker-compose_zeebe-track_1 exited with code 2
docker-compose_zeebe-simple-monitor_1 exited with code 1

stack trace snippets from zeebe-track

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'zeebeSimpleMonitorApp': Invocation of init method failed; nested exception is org.springframework.data.mongodb.UncategorizedMongoDbException: Query failed with error code 13 and error message 'command find requires authentication' on server mongo:27017; nested exception is com.mongodb.MongoQueryException: Query failed with error code 13 and error message 'command find requires authentication' on server mongo:27017

Caused by: com.mongodb.MongoQueryException: Query failed with error code 13 and error message 'command find requires authentication' on server mongo:2701

stack trace snippets for simple-monitor

2020-01-11 20:46:15.404 INFO 1 --- [l'}-mongo:27017] org.mongodb.driver.cluster : Monitor thread successfully connected to server with description ServerDescription{address=mongo:27017, type=STANDALONE, state=CONNECTED, ok=true, version=ServerVersion{versionList=[4, 2, 2]}, minWireVersion=0, maxWireVersion=8, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=25376579}
2020-01-11 20:46:17.784 INFO 1 --- [ main] i.z.zeebemonitor.ZeebeSimpleMonitorApp : initialize connection
2020-01-11 20:46:17.962 INFO 1 --- [ main] org.mongodb.driver.connection : Opened connection [connectionId{localValue:2, serverValue:2}] to mongo:27017
2020-01-11 20:46:18.073 WARN 1 --- [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'zeebeSimpleMonitorApp': Invocation of init method failed; nested exception is org.springframework.data.mongodb.UncategorizedMongoDbException: Query failed with error code 13 and error message 'command find requires authentication' on server mongo:27017; nested exception is com.mongodb.MongoQueryException: Query failed with error code 13 and error message 'command find requires authentication' on server mongo:27017
2020-01-11 20:46:18.086 INFO 1 --- [ main] org.mongodb.driver.connection : Closed connection [connectionId{localValue:2, serverValue:2}] to mongo:27017 because the pool has been closed.
2020-01-11 20:46:18.110 INFO 1 --- [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
2020-01-11 20:46:18.160 INFO 1 --- [ main] ConditionEvaluationReportLoggingListener :

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'zeebeSimpleMonitorApp': Invocation of init method failed; nested exception is org.springframework.data.mongodb.UncategorizedMongoDbException: Query failed with error code 13 and error message 'command find requires authentication' on server mongo:27017; nested exception is com.mongodb.MongoQueryException: Query failed with error code 13 and error message 'command find requires authentication' on server mongo:27017

Remote Camunda Kafka usage

Was looking through the use cases here where the examples show how to use the embedded camunda to talk to Kafka

We have a use case where a remote Camunda cluster would be used for service orchestration across multiple use cases.
In such cases we would have a flow where the remote service may send/receive messages to the event bus and remote Camunda would need to process these messages..
Also the same or diff workflow can talk to different kafka topics and send /receive diff events
What are the options in such cases when designing the workflow?

i)Send task to send messages?
iiReceive task-but can we receive messages from diff topics within the same workflow?How do we handle kafka topic offset reset in case of retries etc in such cases?
iii) Have a customized service task to handle kafka communication , deployed in the remote engine ? This lets us throw in some JSON customization,error handling etc . This approach is sort of what we are leaning towards now.

iv)Create a custom kafka connector?

Cannot create a session after the response has been committed

Running java project from dos command prompt or within intellij results in this error when processing the request

ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
java.lang.IllegalStateException: Cannot create a session after the response has been committed

zeebe docker

Hi,

Do you have an docker compose for "zeebe" parts ?

Regards

Order & Payment doesn't run

I execute the commands:

mvn -f order exec:java -D exec.mainClass="io.flowing.retail.order.OrderApplication"
mvn -f payment exec:java -D exec.mainClass="io.flowing.retail.payment.PaymentApplication"

Caused by: javax.servlet.ServletException: Could not read security filter config file '/securityFilterRules.json': no such resource in servlet context.

The microservice doesn't start.

Help me please

Recieved Warning while running sample

Can there warnings be ignored? I just followed the instructions and the sample seems to be running.

WARN 17168 --- [container-0-C-1] .DispatchingStreamListenerMessageHandler : Cannot find a @StreamListener matching for message with id: null

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.