diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 71e5c51fcb7a26ed55b34e202e933ae93b08fc75..c46551df2a0b2532dd7d78cf661927c126ba0215 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -34,3 +34,4 @@ include: - local: "/bowling-game/.gitlab-ci.yml" - local: "/tennis/greenfield-2/.gitlab-ci.yml" - local: "/mastermind/.gitlab-ci.yml" + - local: "/try-monade/.gitlab-ci.yml" diff --git a/README.md b/README.md deleted file mode 100644 index ee2621cd5d8b4161af21693de4346ba40bcc54ec..0000000000000000000000000000000000000000 --- a/README.md +++ /dev/null @@ -1,99 +0,0 @@ -# Twitch live codings - -Ce dépôt Git a pour but de partager les différents ateliers pouvant être réalisés durant les sessions live coding d'Ippon Technologies sur sa chaîne Twitch. - -- [Calendrier des lives](https://calendar.google.com/calendar/embed?src=c_07pbpmtv1a4d0iu48tnm6tl328%40group.calendar.google.com&ctz=Europe%2FParis) _A ajouter à votre agenda en cliquant sur le + en bas_ -- [Chaîne Twitch](https://www.twitch.tv/ippontech) -- [Playlist Youtube (rediffusions)](https://www.youtube.com/playlist?list=PL6IFaLdAcgE3Uj2DYcbbxKJ-9moQe-g0F) - -# Applications - -On code entierement quelques petites applications les lives, n'hésitez pas à nous piquer des idées ! - -- [Borestop](/borestop): Utilisation de la pyramide de tests pour apporter rapidement de la valeure -- [PadBowl](https://gitlab.com/cdamon/padbowl): "Utilisation" du DDD dans une application basée sur JHipster -- [NERP](https://gitlab.com/cdamon/nerp): Utilisation des méthodologies présentées sur la chaine pour construire totalement une application (en cours) - -# Kata - -Un kata de code est un petit exercice pensé pour s'entrainer jusqu'à maitriser une compétence donnée. - -## Java - -### Facile - -- [RomanNumerals](/roman-numerals) -- [Pagination Seven](/java-pagination-seven) -- [Mustache Replacer](/mustache-replacer) -- [Fizz Buzz](/fizz-buzz) -- [Leap years](/leap-years) -- [Employee report](/employee-report) - -### Moyen - -- [WordWrap](/word-wrap) -- [StringCalculator](/string-calculator) -- [UglyTrivia](/ugly-trivia) -- [Trip service](/trip-service-kata) -- [String calculator 2](/string-calculator-2) -- [TCR - Roman Numerals](/tcr-roman-numerals) -- [H2G2](/java-h2g2) -- [Puissance 4](/puissance-4) -- [CodingGame Mars Landing Party](https://www.youtube.com/watch?v=FeJa3UnmeHw) -- [Movie rental](/movie-rental) -- [Bowling Game](/bowling-game) -- [Tennis Refactoring kata](/tennis/refactoring) - -### Énervé - -- [GildedRose](/gilded-rose) -- [Game of life](/game-of-life) -- [Gilded rose without flow control](/gilded-rose-without-flow-control) - -## TypeScript - -### Moyen - -- [Pagination Seven](/pagination-seven) -- [A Brief History of Date](/a-brief-history-of-date) -- [Trip service (TypeScript)](/trip-service-kata-typescript) -- [Roman calculator](/roman-calculator) -- [H2G2](/h2g2) -- [Mastermind](/mastermind) - -## Front - -### Moyen - -- [Atomic Design I and II](https://gitlab.ippon.fr/arey/pattern-library) - -# Code & coffee - -## Java - -### Facile - -- [Factory patterns](/factory-patterns) -- [Exceptions](/exceptions) - -### Moyen - -- [Java streams](/java-streams) - -### Énervé - -- [Concurrence en Java](/java-concurrence) - -# Discussions et présentations - -- [C'est une bonne situation ça techlead ?](https://www.youtube.com/watch?v=9tOoXfOE12o) -- [GreenIT: simple coup de peinture ou réelle démarche écologique ?](https://www.youtube.com/watch?v=liTuZZTCpGc) -- [Une annonce pour recruter un crafter - Caroline, Chloé, Ianic et Colin](https://www.youtube.com/watch?v=E5AX6Ar1Fog) -- [Proxifier son localhost avec un nginx dockerisé avec Edouard CATTEZ](https://www.youtube.com/watch?v=qWMfRb3zK7k) -- [Dev pour des data scientists, un sale boulot](https://www.youtube.com/watch?v=QK3OJGAresE) -- [Back from GDCR avec Maxime, Séraphin, Anthony et Colin](https://www.youtube.com/watch?v=CHfUGdnSX6I) -- [Résilience des data pipelines](https://youtu.be/xvpUHAWN_fg) -- [1 an de craft chez Prismea](https://youtu.be/8x9_hpL0jj0) -- [Retour sur les 3 jours de conférences de DDD Europe](https://youtu.be/sDUuDpnLWXs) -- [Du craft dans mon code : de la valeur sur ma prod !](https://youtu.be/JvrNRbZhtHo) -- [Le craft au travers d'une jeune équipe de développement](https://youtu.be/ED0dyPHW3VU) diff --git a/package-lock.json b/package-lock.json index b4fba44d02d2c5e9cd732c0cc687824682a0f410..d6d6ff4a87e60a8529c29f52dc28f4ca97d06813 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1342,6 +1342,14 @@ "requires": { "chevrotain": "6.5.0", "lodash": "4.17.15" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + } } }, "js-yaml": { @@ -1635,9 +1643,9 @@ } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, "log-symbols": { @@ -2141,6 +2149,12 @@ "prettier": "1.18.2" }, "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, "prettier": { "version": "1.18.2", "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz", diff --git a/readme.md b/readme.md index e807f8b2974ffb73faf88a97a64b4104af4caf0a..05d9413804bb899cc21b2b7c7b51a337b6148114 100644 --- a/readme.md +++ b/readme.md @@ -12,6 +12,7 @@ On code entierement quelques petites applications les lives, n'hésitez pas à n - [Borestop](/borestop): Utilisation de la pyramide de tests pour apporter rapidement de la valeure - [PadBowl](https://gitlab.com/cdamon/padbowl): "Utilisation" du DDD dans une application basée sur JHipster +- [NERP](https://gitlab.com/cdamon/nerp): Utilisation des méthodologies présentées sur la chaine pour construire totalement une application (en cours) # Kata @@ -58,6 +59,7 @@ Un kata de code est un petit exercice pensé pour s'entrainer jusqu'à maitriser - [Trip service (TypeScript)](/trip-service-kata-typescript) - [Roman calculator](/roman-calculator) - [H2G2](/h2g2) +- [Mastermind](/mastermind) ## Front @@ -81,8 +83,7 @@ Un kata de code est un petit exercice pensé pour s'entrainer jusqu'à maitriser ### Énervé - [Concurrence en Java](/java-concurrence) - -## TypeScript +- [Try monade](/try-monade) # Discussions et présentations diff --git a/try-monade/.gitlab-ci.yml b/try-monade/.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..17af7fa132f749f0ce937dccd6ebefa7b8020d6c --- /dev/null +++ b/try-monade/.gitlab-ci.yml @@ -0,0 +1,11 @@ +package-try-monade: + variables: + PROJECT_FOLDER: "try-monade" + extends: .java + only: + refs: + - master + - merge_requests + changes: + - ".gitlab-common-ci.yml" + - "try-monade/**/*" diff --git a/try-monade/pom.xml b/try-monade/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..fe003c758c3707bb5557dc20844c8d6ef02e7c7f --- /dev/null +++ b/try-monade/pom.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <version>1.0.0</version> + <groupId>fr.ippon.kata</groupId> + <artifactId>java-parent</artifactId> + <relativePath>../java-parent</relativePath> + </parent> + + <version>1.0.0-SNAPSHOT</version> + <artifactId>try-monade</artifactId> + + <name>TryMonade</name> + + <developers> + <developer> + <email>arey@ippon.fr</email> + <name>Anthony REY</name> + </developer> + <developer> + <email>cdamon@ippon.fr</email> + <name>Colin DAMON</name> + </developer> + </developers> +</project> diff --git a/try-monade/readme.md b/try-monade/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..7c78828eb33ba8197c975a072aea92ca2a8c999b --- /dev/null +++ b/try-monade/readme.md @@ -0,0 +1,9 @@ +# Try monade + +Création d'une monade pour gérer les exceptions pendant un code & coffee + +- **Auteurs** : Anthony REY et Colin DAMON +- **Date** : 14/04/2021 +- **Langage** : Java +- **Niveau** : Énervé +- **Replay** : TODO diff --git a/try-monade/src/main/java/fr/ippon/craft/ExecutionException.java b/try-monade/src/main/java/fr/ippon/craft/ExecutionException.java new file mode 100644 index 0000000000000000000000000000000000000000..e6ce0c9a5acd733a975191df05c01031b1c4a83e --- /dev/null +++ b/try-monade/src/main/java/fr/ippon/craft/ExecutionException.java @@ -0,0 +1,8 @@ +package fr.ippon.craft; + +public class ExecutionException extends RuntimeException { + + public ExecutionException(Throwable e) { + super(e); + } +} diff --git a/try-monade/src/main/java/fr/ippon/craft/Faillable.java b/try-monade/src/main/java/fr/ippon/craft/Faillable.java new file mode 100644 index 0000000000000000000000000000000000000000..b45ece07ca69fa1dbded069e4a055f32785d5135 --- /dev/null +++ b/try-monade/src/main/java/fr/ippon/craft/Faillable.java @@ -0,0 +1,6 @@ +package fr.ippon.craft; + +@FunctionalInterface +public interface Faillable<T> { + T execute() throws Throwable; +} diff --git a/try-monade/src/main/java/fr/ippon/craft/Try.java b/try-monade/src/main/java/fr/ippon/craft/Try.java new file mode 100644 index 0000000000000000000000000000000000000000..f051986e01a27d51ea704af2441a2226ad1e4fc0 --- /dev/null +++ b/try-monade/src/main/java/fr/ippon/craft/Try.java @@ -0,0 +1,95 @@ +package fr.ippon.craft; + +import java.util.Objects; +import java.util.function.Function; + +public abstract class Try<T> { + + public static <T> Try<T> of(Faillable<T> failable) { + try { + T result = failable.execute(); + + return new SuccessfulTry<>(result); + } catch (Throwable e) { + return new FailingTry<>(e); + } + } + + public abstract <R> Try<R> map(Function<T, R> mapper); + + public abstract <R> Try<R> flatMap(Function<T, Try<R>> failable); + + public abstract T get(); + + public abstract T orElse(T recovery); + + public abstract T orElseGet(Faillable<T> failing); + + private static class SuccessfulTry<T> extends Try<T> { + private final T result; + + private SuccessfulTry(T result) { + this.result = result; + } + + @Override + public <R> Try<R> map(Function<T, R> mapper) { + Objects.requireNonNull(mapper); + + return new SuccessfulTry<R>(mapper.apply(result)); + } + + @Override + public <R> Try<R> flatMap(Function<T, Try<R>> failable) { + return failable.apply(result); + } + + @Override + public T get() { + return result; + } + + @Override + public T orElse(T recovery) { + return result; + } + + @Override + public T orElseGet(Faillable<T> failing) { + return result; + } + } + + private static class FailingTry<T> extends Try<T> { + private final Throwable e; + + private FailingTry(Throwable e) { + this.e = e; + } + + @Override + public <R> Try<R> map(Function<T, R> mapper) { + return new FailingTry<>(e); + } + + @Override + public <R> Try<R> flatMap(Function<T, Try<R>> failable) { + return new FailingTry<>(e); + } + + @Override + public T get() { + throw new ExecutionException(e); + } + + @Override + public T orElse(T recovery) { + return recovery; + } + + @Override + public T orElseGet(Faillable<T> failing) { + return Try.of(failing).get(); + } + } +} diff --git a/try-monade/src/test/java/fr/ippon/craft/TryTest.java b/try-monade/src/test/java/fr/ippon/craft/TryTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b921b74cf865a2ae6d7cdaf949711eaf386e5f86 --- /dev/null +++ b/try-monade/src/test/java/fr/ippon/craft/TryTest.java @@ -0,0 +1,95 @@ +package fr.ippon.craft; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class TryTest { + + @Test + void shouldCreateSuccessTry() { + assertThat(Try.of(() -> "Yeah").get()).isEqualTo("Yeah"); + } + + @Test + void shouldCreateFaillingTry() { + assertThatThrownBy(() -> Try.of(failing()).get()) + .isExactlyInstanceOf(ExecutionException.class) + .hasCauseExactlyInstanceOf(RuntimeException.class); + } + + @Test + void shouldGetGoodResultForSuccess() { + assertThat(Try.of(() -> "Yeah").orElse("Hey")).isEqualTo("Yeah"); + } + + @Test + void shouldGetAlternativeResultWhenFailing() { + assertThat(Try.of(failing()).orElse("Hey")).isEqualTo("Hey"); + } + + @Test + void shouldMapSuccessfulResult() { + assertThat(Try.of(sucess()).map(Result::new).get()).isEqualTo(new Result("Hello")); + } + + @Test + void shouldNotMapFailingResult() { + Try<Result> tryable = Try.of(failing()).map(Result::new); + + assertThatThrownBy(tryable::get).isExactlyInstanceOf(ExecutionException.class).hasCauseExactlyInstanceOf(RuntimeException.class); + } + + @Test + void shouldFlatMapSuccessfulTry() { + assertThat(Try.of(sucess()).flatMap(value -> Try.of(() -> value + " You")).get()).isEqualTo("Hello You"); + } + + @Test + void shouldFlatMapOnFailingTry() { + Try<String> failing = Try.of(failing()).flatMap(value -> Try.of(() -> value + " You")); + + assertThatThrownBy(failing::get).isExactlyInstanceOf(ExecutionException.class).hasCauseExactlyInstanceOf(RuntimeException.class); + } + + @Test + void shouldFlatMapWithFailingTry() { + assertThatThrownBy(Try.of(sucess()).flatMap(value -> Try.of(failing()))::get) + .isExactlyInstanceOf(ExecutionException.class) + .hasCauseExactlyInstanceOf(RuntimeException.class); + } + + @Test + void shouldNotGetorElseForSuccessfulTry() { + assertThat(Try.of(sucess()).orElseGet(() -> "Fallback")).isEqualTo("Hello"); + } + + @Test + void shouldNotGetFaillingOrElseGet() { + assertThat(Try.of(sucess()).orElseGet(failing())).isEqualTo("Hello"); + } + + @Test + void shouldGetOrElseGetOnFaillingTry() { + assertThat(Try.of(failing()).orElseGet(sucess())).isEqualTo("Hello"); + } + + @Test + void shouldFailOrElseGetOnFaillingTry() { + assertThatThrownBy(() -> Try.of(failing()).orElseGet(failing())) + .isExactlyInstanceOf(ExecutionException.class) + .hasCauseExactlyInstanceOf(RuntimeException.class); + } + + private Faillable<String> sucess() { + return () -> "Hello"; + } + + private Faillable<String> failing() { + return () -> { + throw new RuntimeException(); + }; + } + + private static record Result(String value) {} +}