Skip to content

Commit

Permalink
Enhance document
Browse files Browse the repository at this point in the history
  • Loading branch information
arowM committed Jul 20, 2023
1 parent 1b6442b commit 99745c9
Show file tree
Hide file tree
Showing 3 changed files with 277 additions and 29 deletions.
220 changes: 217 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,224 @@
# TEPA - The Elm Procedure Architecture
# TEPA

[![test](https://github.com/arowM/tepa/actions/workflows/test.yaml/badge.svg)](https://github.com/arowM/tepa/actions/workflows/test.yaml)
[Document](https://package.elm-lang.org/packages/arowM/tepa/latest/)

![logo](https://user-images.githubusercontent.com/1481749/115139779-de382400-a06e-11eb-80e7-22af97774bfa.jpg)

TEPA is a web application framework for creating applications with user-centered design, built on TEA.
TEPA is a framework for building user-centric web applications through scenario-driven development.

This framework is under development. You can see library document by `npm start`, and a sample application in `spa-sample`.
## What TEPA can do?

TEPA has three main features:

* Generate scenario document
* Generate scenario test
* Develop robust web application with chronological description

### Generate Scenario Document

The `Tepa.Scenario` module allows you to programmatically describe scenario documents.
The resulting document can be viewed in real time in a web browser as a document server, or saved as a markdown file.

Sample Scenario:

```elm
...
, onSakuraChanMainSession.login.expectAvailable <|
Scenario.textContent "Display login page."
, userComment sakuraChan
"I see I have to log in! I remember my dad gave me the account information beforehand."
, onSakuraChanMainSession.login.expectLoginFormShowNoErrors <|
Scenario.textContent "The login form shows no errors at first."
, userComment yabugarashiKun
"I'm Yabugarashi-kun. I'm going to play a prank on Sakura-chan. Muahahahahaha! 😈"
, userComment yabugarashiKun
"Sakura-chan, here is the account information note your father gave you. 😈"
, userComment sakuraChan
"Thank you, Yabugarashi-kun. 🌸"
, onSakuraChanMainSession.login.changeLoginId
{ value = "guest"
}
(Scenario.textContent "Login ID entered.")
, userComment sakuraChan
"The note says that the password can be left blank."
, onSakuraChanMainSession.login.clickSubmitLogin
(Scenario.textContent "Clicked the login button.")
, let
error =
"Password is required."
in
onSakuraChanMainSession.login.expectLoginFormShowError
{ error = error
}
(Scenario.textContent <| "Form shows error: " ++ error)
, userComment sakuraChan
"Oh my goat, I got an error..."
, userComment yabugarashiKun
"Sorry, sorry, I just got a little naughty. Here's the real note."
, userComment sakuraChan
"Okay, I'll try again."
, let
value =
"fuestPass"
in
onSakuraChanMainSession.login.changeLoginPass
{ value = value
}
(Scenario.textContent <| "Password changed to \"" ++ value ++ "\"")
, onSakuraChanMainSession.login.expectLoginFormShowNoErrors
(Scenario.textContent "Login form shows no errors at the time.")
, userComment sakuraChan
"It looks good."
, onSakuraChanMainSession.login.clickSubmitLogin
(Scenario.textContent "Clicked the login button.")
...
```

Generated markdown:

```elm
...
* **\[Sakura\-chan's main session\]** **System**: Display login page.
* **Sakura\-chan**: I see I have to log in\! I remember my dad gave me the account information beforehand.
* **\[Sakura\-chan's main session\]** **System**: The login form shows no errors at first.
* **Yabugarashi\-kun**: I'm Yabugarashi\-kun. I'm going to play a prank on Sakura\-chan. Muahahahahaha\! 😈
* **Yabugarashi\-kun**: Sakura\-chan, here is the account information note your father gave you. 😈
* **Sakura\-chan**: Thank you, Yabugarashi\-kun. 🌸
* **\[Sakura\-chan's main session\]** **Sakura\-chan**: Login ID entered.
* **Sakura\-chan**: The note says that the password can be left blank.
* **\[Sakura\-chan's main session\]** **Sakura\-chan**: Clicked the login button.
* **\[Sakura\-chan's main session\]** **System**: Form shows error: Password is required.
* **Sakura\-chan**: Oh my goat, I got an error...
* **Yabugarashi\-kun**: Sorry, sorry, I just got a little naughty. Here's the real note.
* **Sakura\-chan**: Okay, I'll try again.
* **\[Sakura\-chan's main session\]** **Sakura\-chan**: Password changed to "fuestPass"
* **\[Sakura\-chan's main session\]** **System**: Login form shows no errors at the time.
* **Sakura\-chan**: It looks good.
* **\[Sakura\-chan's main session\]** **Sakura\-chan**: Clicked the login button.
...
```

In scenario-driven development, which TEPA advocates, the first step is to imagine a concrete use case and create a scenario, and in team development using GitHub, etc., the markdown output of the scenario can be included in pull requests so that reviewers can compare it to the current scenario and see what has changed. Reviewers can easily see what has changed from the current scenario.

### Generating Scenario Tests

By describing scenarios with the `Tepa.Scenario` module, you can automatically test that your TEPA application behaves as described in the scenario. All real world effects like HTTP responses, random numbers, and passage of time, e.t.c., will be simulated as described in the scenario.

### Develop robust web application with chronological description

Static analysis is an essential technique for building reliable and robust applications. To make static analysis more powerful, strong static types are used. However, some languages with strong static types have a feature known as exceptions. This feature negates the benefits of static typing.

One way to enable strong, statically typed, exception-free programming is [The Elm Architecture](https://guide.elm-lang.org/architecture/)(TEA).
The basic design of TEA is great, but using TEA as it is, it is difficult to create user-centric design applications. This is because TEA describes the application by data-centric design, which determines the next process and state based only on the current state of the application when some events (such as user operation) have occurred. On the other hand, real user behavior is an extension of their previous operations, so creating a user-centric application requires a framework that wraps TEA to make it specialized for that use.

TEPA provides such a dedicated framework, which is closer to a scenario because it allows applications to be described in chronological order. As a result, it inherits the features of imperative programming, which facilitates user-centered design, and the features of functional programming, which facilitates static analysis.

```elm
submitLoginProcedure : Bucket -> Promise Memory ()
submitLoginProcedure bucket =
let
modifyLoginForm f =
Tepa.modify <|
\m ->
{ m | loginForm = f m.loginForm }
in
Tepa.sequence
[ modifyLoginForm <|
\m -> { m | isBusy = True }
, Tepa.bind Tepa.getValues <|
\form ->
case Login.fromForm form of
Err _ ->
[ modifyLoginForm <|
\m ->
{ m
| isBusy = False
, showError = True
}
]

Ok login ->
[ Tepa.bind (Login.request login) <|
\response ->
case response of
Login.TemporaryErrorResponse ->
[ Tepa.syncAll
[ Toast.pushError
"Network error, please check your network and try again."
|> runToastPromise
|> Tepa.void
, Tepa.sequence
[ modifyLoginForm <|
\m ->
{ m | isBusy = False }
]
]
]

Login.FatalErrorResponse ->
[ Tepa.syncAll
[ Toast.pushError
"Internal error, please contact our support team."
|> runToastPromise
|> Tepa.void
, Tepa.sequence
[ modifyLoginForm <|
\m ->
{ m | isBusy = False }
]
]
]

Login.IncorrectIdOrPasswordResponse ->
[ modifyLoginForm <|
\m ->
{ m
| isBusy = False
, incorrectIdOrPass = True
, showError = True
}
]

Login.GoodResponse resp ->
[ Tepa.bind (Random.request Session.randomLuckyHay) <|
\luckyHay ->
[ Tepa.modify <|
\m ->
{ m
| msession =
Just
{ profile = resp.profile
, luckyHay = luckyHay
}
, loginForm =
let
loginForm =
m.loginForm
in
{ loginForm
| isBusy = False
}
}
]
, Nav.pushPath bucket.key
(bucket.requestPath.queryParameters
|> Dict.get "back"
|> Maybe.andThen List.head
|> Maybe.andThen Path.toAppUrl
|> Maybe.withDefault
{ path =
[ Path.prefix
]
, queryParameters = Dict.empty
, fragment = Nothing
}
)
]
]
]
```

## Getting started

We are preparing a tutorial. You can check a sample application in the `spa-sample` directory.
2 changes: 1 addition & 1 deletion elm.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"type": "package",
"name": "arowM/tepa",
"summary": "Web application framework for creating applications with user-centered design",
"summary": "Framework for building user-centric apps through scenario-deriven development",
"license": "MIT",
"version": "1.0.0",
"exposed-modules": [
Expand Down
Loading

0 comments on commit 99745c9

Please sign in to comment.