Back to Docs
# Modern Microservices <!-- .slide: data-background-image="/images/presentations/ppt-background.png" --> <p> <i class="fa-solid fa-bullhorn primary-text"></i> Mike Lucas </p> <img class="power-on" src="/images/presentations/Power_On_RGB.png"/> --- # Questions Please raise any questions in the Q/A section in Conference +. We will address the questions as soon as possible. Note: If you're watching this session live with us, we will be doing our best to reply to your questions in the background or live during this session. If you're watching the recording, we have a team on the call ready to respond to questions, so please ask away. --- <!-- Speaker Details --> <div class="container"> <div class="row speaker-details"> <div class="col-5"> <div class="shape-container"> <div class="shape"> <div id="speaker" class="rounded-circle speaker-image neon" style="background: url('/images/presentations/microservices/speaker_mike_lucas.JPG') no-repeat;"></div> </div> </div> </div> <div class="col"> <h2>Mike Lucas</h2> <h4>Chief Data Platform Architect</h4> <ul class="fancy-list"> <li>10+ Years @ Finastra</li> <li>Helping guide data-centric transformations for Finastra products</li> </ul> <p>Python, .NET, Java, NodeJS, Terraform, and many others, <br/><u>+ always looking to grow</u></p> </div> </div> </div> --- # Agenda <ul class="fragment fancy-list" data-fragment-index="1"> <li>The Future of Finance</li> <li>Modern Microservices</li> <li>Monolith Decomposition Strategies</li> <li>FusionFabric.cloud & Product Extensibility</li> <li><b><i>The TechCon App</i></b> <ul class="fragment" data-fragment-index="2"> <li>Background & Feature Requirements</li> <li>Setting up Codespaces</li> <li>Architecture</li> <li>Test-Driven Implementation Of A Feature</li> </ul> </li> </ul> Note: First, we're going to talk about how we as Finastra can spearhead the 'Future of Finance'. Next, we're going to dive into some background review around microservices, and talk about how we close the gap from monolith to microservice. Then we'll discuss how the FusionFabric.cloud platform enables us to do this in a secure and consistent manner. Finally, we're going to dive into an actual sample microservice we created especially for TechCon to show you the power of microservices, and get you hands-on with test-driven development of a microservice feature. --- # Future of Finance <!-- .slide: data-background-image="/images/presentations/ppt-background.png" --> ___ # Future of Finance <div class="container"> <p>At Finastra, the <u>Future of Finance</u> sits on <strong>3 pillars</strong>:</p><br/> <div class="row"> <div class="col-5 fragment" data-fragment-index="1"> <ul class="fancy-list larger"> <li><h3>Modern UX</h3></li> <li><h3>Data & AI</h3></li> <li><h3>Cloud-Native Microservices</h3></li> </ul> </div> <div class="col fragment text-align-left" data-fragment-index="2"> This session will demonstrate how your product can add innovation using Microservices & FusionFabric.cloud. <br/> <br/> <ul class="fancy-list"> <li>Introduce brand new functionality</li> <li>Isolate, and incrementally rewrite existing functionality</li> <li>Achieve `speed of delivery` (testing, scaling, all independent of each other)</li> </ul> </div> </div> </div> Note: --- # Why Microservices? <!-- .slide: data-background-image="/images/presentations/ppt-background.png" --> ___ # Why Microservices? <!-- .slide: class="multi-columns wide" --> <div class="container"> <p> <strong>Goal:</strong> Accelerate software development rate of change<br/> <strong>Tactic:</strong> Loosely coupled, independently changeable services </p><br/> <div class="row"> <div class="col col-6"> <img src="/images/presentations/microservices/success_triangle_for_software.png"/> </div> <div class="col col-6 fragment" data-fragment-index="1"> <h2>Outcomes</h2> <ul class="fancy-list"> <li>Simplifies testing and enables components to changed independently</li> <li>Structures the engineering organization to optimize collaboration and developer productivity</li> <li>Improves quality, efficiency, and time-to-market</li> </ul> </div> </div> </div> Note: ___ # Benefits <!-- .slide: class="multi-columns wide" --> <div class="container"> <p>Microservices enable us to achieve quality, efficiency, & time-to-market with the our products.</p><br/> <div class="row"> <div class="col fragment" data-fragment-index="1"> <h2>Quality</h2> <ul class="fancy-list"> <li>Single codebase & domain/service-centric design</li> <li>Highly maintainable & testable</li> <li>Improved fault isolation</li> </ul> </div> <div class="col fragment" data-fragment-index="2"> <h2>Efficiency</h2> <ul class="fancy-list"> <li>New team members can become productive quickly</li> <li>Application is easy to understand and modify</li> <li>Developed by a small and self-reliant team</li> </ul> </div> <div class="col fragment" data-fragment-index="3"> <h2>Time to Market</h2> <ul class="fancy-list"> <li>Rapid and frequent deployment</li> <li>Independently deployable from other services</li> <li>Leverage emerging technologies; small enough to keep up-to-date</li> <li>Reduced risk of change</li> </ul> </div> </div> </div> Note: These benefits are realized by a number of traits that come along with a well-designed microservice. ... Next, we're going to talk about how we start the process of breaking down our monoliths into smaller microservices, and how we can begin modernizing our applications while still delivering the day-to-day bug fixes and feature enhancements our customers need. ___ # My product is currently a monolith ### How do I make the transition? <!-- .slide: data-background-image="/images/presentations/ppt-background.png" --> ___ # Introducing Innovation ## Primary Tactic <div class="container"> <br/> <div class="row"> <div class="col"></div> <div class="col col-9 fragment" data-fragment-index="2"> <h3>Introduce an anti-corruption layer (ACL)</h3> <ul class="fancy-list text-align-left"> <li>Define incoming and outgoing API contracts between the product and new microservices <ul> <li>Incoming = <strong>API</strong></li> <li>Outgoing = <strong>SPI</strong></li> </ul> </li> <li>Update the product to use the ACL facade</li> <li>Ensure any new functionality uses the ACL facade</li> </ul> </div> <div class="col"></div> </div> Note: It's all about how we want to isolate change. ... The differentiating point is that on the left, we are emphasizing a sellable vertical slice, versus on the right, while we don't get a complete vertical slice, we instead emphasize separation between technical components in a subsystem. ... This is a fancy way of saying "just be intentional about loose coupling". Do not build dependencies into your product that will make testing and change difficult or risky. ___ # Monolith Decompositions <!-- .slide: class="multi-columns wide" --> <div class="container"> <h2>Strategies</h2> <br/> <br/> <div class="row"> <div class="col fragment" data-fragment-index="1"> <h3>Decompose by Business Capability</h3> <p>[ business-centric thinking ]</p> <p>Segregate by something that a business does in order to generate <b><i>value</i></b></p> <br/> <h6>examples:</h6> <ul> <li><small><b><i>High-Value Payments</i></b> is responsible for processing high-value payments</small></li> <li><small><b><i>Immediate Payments</i></b> is responsible for processing immediate payments</small></li> </ul> </div> <div class="col fragment" data-fragment-index="2"> <h3>Decompose by Subdomain</h3> <p>[ developer-centric thinking ]</p> <p>Segregate by different areas of <b><i>technical expertise.</i></b><br/> architectural bounded contexts</p> <br/> <h6>examples:</h6> <ul> <li><small><b><i>Liquidity Management</i></b> is responsible for liquidity management</small></li> <li><small><b><i>Upfront Enrichment & Validation</i></b> is responsible for preprocessing payment information</small></li> </ul> </div> </div> </div> Note: Keep in mind that regardless of strategy, our objective remains to break our monolith down into chunks. This way, as business rules change, developers only need to change code in a small number - ideally only one - of the services. Once we've successfully identified our microservice domains, we're still left with a major challenge: > **How do we modernize the application without disappearing for months or years to rewrite the application from the ground-up?** Next we'll talk about how to achieve a controlled transition to microservices, using an approach called the **`Strangler Pattern`**. ___ # Controlled Transition <!-- .slide: class="multi-columns wide" --> <div class="container"> <p> The <b><i>Strangler Pattern</i></b> allows us to incrementally migrate a legacy system by gradually replacing specific pieces of functionality with new applications and services. </p><br/> <div class="row"> <div class="col col-8 fragment" data-fragment-index="1"> <img src="/images/presentations/microservices/strangler-facade.png"/> <i class="annotation fragment" data-fragment-index="2" style="left:11px; top:60px">1</i> <i class="annotation fragment" data-fragment-index="3" style="left:507px;top:140px;">2</i> <i class="annotation fragment" data-fragment-index="4" style="left:719px;top:60px;">3</i> </div> <div class="col col-4"> <blockquote class="annotation fragment" data-number="1" data-fragment-index="2"> The product is put behind an intermediary ACL facade. </blockquote> <blockquote class="annotation fragment" data-number="2" data-fragment-index="3"> Over time, existing features are replaced by microservices. </blockquote> <blockquote class="annotation fragment" data-number="3" data-fragment-index="4"> Eventually, the microservices replace the original monolith and the facade can be removed. </blockquote> </div> </div> <div class="row fragment" data-fragment-index="9"> <!-- <div class="col"></div> --> <div class="col-5"> <blockquote class="reference-link"> <b>Finastra Learning Paths</b><br/> <a target="_blank" href="https://app.pluralsight.com/library/courses/your-microservices-transition/table-of-contents">Pluralsight: Your Microservice Transition</a> </blockquote> </div> <!-- <div class="col"></div> --> </div> </div> Note: [ we've talk about how we ... ] now that we have a pattern to add new functionality, how do we address challenges like customer-specific logic? of the patterns, we're going to focus on SPIs, because we're focused on adding new functionality to products, rather than a decomposition story but I wanted to take a couple minutes to highlight how we see SPIs being used for product extensibility, specifically customer-specific logic Now to get us back into our specific journey ___ # FusionFabric.cloud <!-- .slide: data-background-image="/images/presentations/ppt-background.png" --> ### Product Extensibility ___ <!-- FusionFabric.cloud --> <h1 style="line-height: 38px;">F<small>usion</small>F<small>abric</small>.<small>cloud</small></h1> <h4 class="subheader">Innovate for the future of finance</h4> <!-- .slide: class="multi-columns wide" --> <div class="container"> <br/> <br/> <div class="row"> <div class="col col-4 fragment" data-fragment-index="1"> <h4>API</h4> <img src="/images/presentations/microservices/api-models-api-rev.png"/> <br/><br/> <ul class="fancy-list"> <li><small>Synchronous call from a <u>client application</u> to a Finastra product. <strong>One-to-One</strong></small></li> <li><small>You develop the client application that calls APIs exposed by the product, which are compliant with an OpenAPI specification.</small></li> </ul> </div> <div class="col col-4 fragment" data-fragment-index="2"> <h4>API Events</h4> <img src="/images/presentations/microservices/api-models-events-rev.png"/> <ul class="fancy-list"> <li><small>Asynchronous call from a <u>Finastra product</u> to all subscribed client applications. <strong>One-to-Many</strong></small></li> <li><small>You develop the client application and register with a webhook that sends event notifications compliant to the Events API specification provided by a product.</small></li> <li><small>The product sends the messages through the base URL that you register on FusionFabric.cloud.</small></li> </ul> </div> <div class="col col-4 fragment" data-fragment-index="3"> <h4>SPI</h4> <img src="/images/presentations/microservices/api-models-spi-rev.png"/> <br/> <h5>Enabling Extensibility</h5> <ul class="fancy-list"> <li><small>Synchronous call from a Finastra <u>product</u> to an SPI compliant service for <em>extensibility</em>. <strong>One-to-One</strong></small></li> <li><small>You develop a service compliant to the SPI specification provided by the product.</small></li> <li><small>The service is called by the product through the base URL that you register on FusionFabric.cloud.</small></li> </ul> </div> </div> </div> Note: ___ # SPI #### Service Provider Interface ## In Practice <!-- .slide: class="multi-columns wide" --> <div class="container"> <div class="row"> <!-- <i class="annotation fragment" data-fragment-index="3" style="left:507px;top:140px;">2</i> --> <div class="col fragment" data-fragment-index="2"> <h5 style="margin-bottom: 0">Customer-Specific Logic</h5> <h6 style="color: grey">[ never do this ]</h6> <pre> <i class="annotation fragment" data-fragment-index="2" style="left: -44px;top: 79px;">1</i> <code data-trim data-noescape data-line-numbers="4-10"> <script type="text/template"> protected void handlePayment(Payment payment) { // [ business logic ] ‎ boolean proceedWithPayment = true; ‎ if (customer.name == "abc bank") { if (payment.amount > 100000){ proceedWithPayment = false; } } ‎ if (proceedWithPayment) { // [business logic] } ‎ } </script> </code> </pre> </div> <div class="col fragment" data-fragment-index="3"> <h5 style="margin-bottom: 0">Product Extensibility</h5> <h6 style="color: grey">[ instead, do this ]</h6> <pre> <i class="annotation fragment" data-fragment-index="3" style="left: -50px;top: 132px;">2</i> <code data-trim data-noescape data-line-numbers="4-11"> <script type="text/template"> protected void handlePayment(Payment payment) { // [ business logic ] ‎ // This is an external FFDC API call // from our core application to the customer's // configured SPI endpoint. // // e.g.: This could be used to control whether // a payment should proceed final boolean proceedWithPayment = paymentSpiService.handlePayment(payment) ‎ if (proceedWithPayment) { // [business logic] } ‎ } </script> </code> </pre> </div> <div class="col"> <blockquote class="annotation fragment" data-number="1" data-fragment-index="2"> Customer-specific logic is messy and hard to manage. </blockquote> <blockquote class="annotation fragment" data-number="2" data-fragment-index="3"> SPIs allow us to extend our application dynamically, without customer-specific logic. </blockquote> <blockquote class="fragment text-align-left" style="font-size:.7em" data-fragment-index="3"> The platform supports customer-specific routing, enabling use of custom functionality in an external microservice. </blockquote> </div> </div> </div> Note: --- # The TechCon App <!-- .slide: data-background-image="/images/presentations/ppt-background.png" --> ___ # TechCon App <!-- .slide: class="multi-columns wide" --> ## Intelligent Decisioning <div class="container"> <div class="row"> <div class="col fragment" data-fragment-index="1"> <h3>Background</h3> <p>The TechCon `Decisioning Dashboard` app brings intelligent features to market, in a <br/><strong>fresh & modern UX.</strong></p> <ul class="fancy-list"> <li>Prescriptive Client Experience</li> <li>Actionable Insights</li> <li>Automation</li> </ul> </div> <div class="col fragment" data-fragment-index="2"> <h3>Feature Requirements</h3> <h4><i class="fa-solid fa-comments-dollar"></i> From The Product Team</h4> <p class="text-align-left" style="font-size:.9em; line-height: 2em;" > <i class="fa-solid fa-quote-left"></i>When a loan is submitted to the decisioning dashboard for review, <i class="annotation" style="position:relative;">1</i> the loan needs to be available to be viewed within the dashboard. Additionally, <i class="annotation" style="position:relative;">2</i> that loan needs to be auto-scored for approval, so the user is able to see how likely the loan is to be approved. Lastly, if the likelihood of a loan being approved is too low, <i class="annotation" style="position:relative;">3</i> that loan needs to be automatically rejected and the decision status reported back to the main application <i class="fa-solid fa-quote-right"></i> </p> </div> </div> </div> ___ # Getting Started <!-- .slide: class="multi-columns wide" --> ## Accessing Your GitHub Repo <br/> <div class="container"> <div class="row"> <div class="col col-6"> <h4>1. Accept Via Email</h4> <img src="/images/presentations/org-invite.jpg" style="width:300px"/> <img src="/images/presentations/repo-invite.jpg" style="width:300px"/> </div> <div class="col"> <h4>2. Accept via GitHub Organization Screen</h4> <br/> <img src="/images/presentations/org-invite-github.png"/> </div> </div> </div> ___ # Let's Code! 1. Navigate to https://github.com/finastra-techcon/ 1. Find your pre-provisioned repository > **Naming Convention:** <br>`{your-github-handle}-microservice-java` ___ # Launch Codespaces <img src="/images/presentations/microservices/codespaces/starter-branch.png" style="width:300px"/> <i class="fa-solid fa-angles-right"></i> <img src="/images/presentations/launch-codespaces.png" style="width:500px"/> <i class="fa-solid fa-angles-right"></i> <img src="/images/presentations/codespace-creation.png" style="width:600px"/> ___ # Architecture <!-- .slide: class="multi-columns wide" --> <div class="container"> <div class="row"> <div class="col col-7"> <h6 style="color: grey">[ docker-compose.yml ]</h6> <pre> <code data-trim data-noescape data-line-numbers="2-13|15-23|25-31" style="max-height: 500px"> <script type="text/template"> services: vscode: build: context: . dockerfile: Dockerfile image: result:latest pull_policy: build depends_on: - postgres environment: - JAVA_HOME=/usr/lib/jvm/msopenjdk-current command: sleep infinity network_mode: service:postgres ‎ frontend: image: ghcr.io/finastra-techcon/angular-nestjs-web-components-starter:latest ports: - 3000:3000 environment: - OIDC_CLIENT_ID=${OIDC_CLIENT_ID:?OIDC client ID missing} - OIDC_CLIENT_SECRET=${OIDC_CLIENT_SECRET:?OIDC client secret missing} - CODESPACE_NAME=${CODESPACE_NAME} - GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN=${GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN} ‎ postgres: image: postgres:14.5 ports: - 5432:5432 restart: always environment: POSTGRES_PASSWORD: techcon </script> </code> </pre> </div> <div class="col"> <img src="/images/presentations/microservices/codespaces/codespace-architecture-microservice.png" /> </div> </div> </div> ___ # Import Java Project <!-- .slide: class="multi-columns wide" --> <div class="container"> <div class="row"> <div class="col col-3"> <i class="annotation fragment" data-fragment-index="1" style="left: 50px;top: 115px;">1</i> <i class="annotation fragment" data-fragment-index="2" style="left: 220px;top: 275px;">2</i> <img src="/images/presentations/microservices/codespaces/import-java-project.png" /> <img src="/images/presentations/microservices/codespaces/rebuild-all.png" /> </div> <div class="col"> <blockquote class="annotation fragment" data-number="1" data-fragment-index="1"> Import the Java project </blockquote> <blockquote class="annotation fragment" data-number="2" data-fragment-index="2"> Once loaded, click `Rebuild All` to compile the project </blockquote> </div> </div> </div> ___ # Project Layout <!-- .slide: class="multi-columns wide" --> <div class="container"> <div class="row"> <div class="col col-3"> <i class="annotation fragment" data-fragment-index="1" style="left: 0px;top: 95px;">1</i> <i class="annotation fragment" data-fragment-index="2" style="left: 0px;top: 295px;">2</i> <i class="annotation fragment" data-fragment-index="3" style="left: 0px;top: 575px;">3</i> <i class="annotation fragment" data-fragment-index="4" style="left: 0px;top: 460px;">4</i> <img src="/images/presentations/microservices/codespaces/source-code-layout.png" /> </div> <div class="col"> <blockquote class="annotation fragment" data-number="1" data-fragment-index="1"> <strong>Our main microservice code.</strong> Here we'll find our controllers, services, and business specific models and logic. </blockquote> <blockquote class="annotation fragment" data-number="2" data-fragment-index="2"> Application configuration and database schema management [Flyway]. </blockquote> <blockquote class="annotation fragment" data-number="3" data-fragment-index="3"> Behavior Driven Design (BDD) feature files, and test database schema management [Flyway]. </blockquote> <blockquote class="annotation fragment" data-number="4" data-fragment-index="4"> Test setup and step definitions to support BDD testing. </blockquote> </div> </div> </div> --- # Test-Driven Development <!-- .slide: data-background-image="/images/presentations/ppt-background.png" --> ___ # Intelligent Decisioning <!-- .slide: class="multi-columns wide" --> <div class="container"> <div class="row"> <div class="col fragment" data-fragment-index="1"> <h3>Feature Requirements</h3> <h4><i class="fa-solid fa-comments-dollar"></i> From The Product Team</h4> <p class="text-align-left" style="font-size:.9em;line-height: 2em;" > <i class="fa-solid fa-quote-left"></i>When a loan is submitted to the decisioning dashboard for review, <i class="annotation" style="position:relative;">1</i> the loan needs to be available to be viewed within the dashboard. Additionally, <i class="annotation" style="position:relative;">2</i> that loan needs to be auto-scored for approval, so the user is able to see how likely the loan is to be approved. Lastly, if the likelihood of a loan being approved is too low, <i class="annotation" style="position:relative;">3</i> that loan needs to be automatically rejected and the decision status reported back to the main application <i class="fa-solid fa-quote-right"></i> </p> </div> <div class="col fragment" data-fragment-index="2"> <pre> <code data-trim data-noescape data-line-numbers="1-2|1-8|10-11|10-17|19-20|19-24" style="max-height: 500px"> <script type="text/template"> @positive @loan-reviews Scenario: An authenticated user can submit a loan for review Given a loan reviewer is authenticated And they have a valid loan application When they submit the loan for review Then the loan is submitted for review And they receive a reference identifier to follow up with And the loan application has a confidence score ‎ @positive @loan-reviews Scenario: A decision will be automatically reconciled when an authenticated user submits a [rejectable] loan application Given a loan reviewer is authenticated And they have a loan application that will be automatically rejected When they submit the loan for review Then they receive a reference identifier to follow up with And the loan application has a confidence score And the decision is communicated back to the product application ‎ @negative @loan-reviews Scenario: An unauthenticated user cannot submit an loan for review Given a loan reviewer is not authenticated And they have a valid loan application When they submit the loan for review Then they receive an error indicating that they must be authenticated to submit loans for review </script> </code> </pre> </div> </div> </div> ___ # Executing our Tests <div class="container"> <div class="row"> <div class="col col-8"> <img src="/images/presentations/microservices/codespaces/tests-fail.png" style="width: 100%; height: 550px; object-fit: none; object-position: 0 0"/> </div> <div class="col"> <blockquote class="annotation" data-number="1"> Run your tests. </blockquote> <blockquote> We can see that many tests fail, indicating our application is not behaving as expected. </blockquote> </div> </div> </div> --- # Implementing Events <!-- .slide: data-background-image="/images/presentations/ppt-background.png" --> ___ # Data Flow <!-- .slide: class="multi-columns wide" --> <img src="/images/presentations/microservices/microservice-events.png" /> Note: ___ # Loan Batch Submission <!-- .slide: class="multi-columns wide" --> <div class="container"> <div class="row"> <div class="col col-6"> <h6 style="color: grey;text-transform: inherit">[ /controllers/spi/SpiController.java ]</h6> <pre> <i class="annotation" style="left: -52px;top: 0px;">1</i> <i class="annotation" style="left: -52px;top: 52px;">2</i> <i class="annotation" style="left: -52px;top: 142px;">3</i> <i class="annotation" style="left: -52px;top: 222px;">4</i> <i class="annotation" style="left: -52px;top: 292px;">5</i> <i class="annotation" style="left: -52px;top: 352px;">6</i> <code data-trim data-noescape data-line-numbers="1-2,27|3-7|9-15,26|16-17|20-22|25|1-27" style="max-height: 500px"> <script type="text/template"> @RestController public class SpiController { @Autowired private LoanApplicationService loanApplicationService; ‎ @Autowired private ApplicationEventPublisher eventPublisher; ‎ @PostMapping( path = "/techcon/review-loan-applications/v1/loan-reviews", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<SubmittedLoanApplicationData> submit( @RequestBody(required = true) @Valid ApplicationSubmissionData loanApplications ) { final SubmittedLoanApplicationData submittedLoans = loanApplicationService.persistLoans(loanApplications); ‎ ‎ // here we need to raise a `LoanBatchSubmitted` event to // trigger asynchronous functionality // [ missing code ] ‎ ‎ return ResponseEntity.status(HttpStatus.CREATED).body(submittedLoans); } } </script> </code> </pre> </div> <div class="col"> <blockquote class="annotation" data-number="1"> The <strong>@RestController</strong> annotation marks the class as a specialized controller where method return values are bound to the web response body. </blockquote> <blockquote class="annotation" data-number="2"> The <strong>@Autowired</strong> annotation allows fields to be populated by automatic dependency injection. Dependency injection makes a class independent of its dependencies, which makes testing code easier and reduces coupling within the application. </blockquote> <blockquote class="annotation" data-number="3"> The <strong>@PostMapping</strong> annotation allows us to specify how and where a user interacts with our REST endpoint. In this example, we specify an <strong>API path</strong>, associate an HTTP verb, and define the request/response object types. Also notable is that we mark the request body as <strong>required</strong>, and use the <strong>@Valid</strong> annotation to enforce the request object be validated against its expected schema `ApplicationSubmissionData`. </blockquote> <blockquote class="annotation" data-number="4"> The validated request data is persisted to the database. </blockquote> <blockquote class="annotation" data-number="5"> <strong>TODO:</strong> Raise a `LoanBatchSubmitted` event to trigger asynchronous functionality </blockquote> <blockquote class="annotation" data-number="6"> The newly-persisted data is returned to the user, using the proper HTTP Status Code (in this case <strong>`201 CREATED`</strong>) </blockquote> </div> </div> </div> ___ # Loan Batch Submission <!-- .slide: class="multi-columns wide" --> <div class="container"> <div class="row"> <div class="col col-6"> <h6 style="color: grey;text-transform: inherit">[ /controllers/spi/SpiController.java ]</h6> <pre> <i class="annotation" style="left: -52px;top: 272px;">1</i> <code data-trim data-noescape data-line-numbers="6-7,19-21" style="max-height: 500px"> <script type="text/template"> @RestController public class SpiController { @Autowired private LoanApplicationService loanApplicationService; ‎ @Autowired private ApplicationEventPublisher eventPublisher; ‎ @PostMapping( path = "/techcon/review-loan-applications/v1/loan-reviews", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<SubmittedLoanApplicationData> submit( @RequestBody(required = true) @Valid ApplicationSubmissionData loanApplications ) { final SubmittedLoanApplicationData submittedLoans = loanApplicationService.persistLoans(loanApplications); ‎ eventPublisher.publishEvent( new LoanBatchSubmitted(this, submittedLoans.getLoanApplications()) ); ‎ return ResponseEntity.status(HttpStatus.CREATED).body(submittedLoans); } } </script> </code> </pre> </div> <div class="col"> <blockquote class="annotation" data-number="1"> Using our injected <strong>`ApplicationEventPublisher`</strong>, we can publish an event.<br/> The <strong>LoanBatchSubmitted</strong> contains the batch set of loans submitted. </blockquote> </div> </div> </div> ___ # Data Flow <!-- .slide: class="multi-columns wide" --> <img src="/images/presentations/microservices/microservice-events-stage1.png" /> Note: ___ # Listening to Events <!-- .slide: class="multi-columns wide" --> <div class="container"> <div class="row"> <div class="col col-7"> <h6 style="color: grey;text-transform: inherit">[ /events/LoanBatchSubmissionListener.java ]</h6> <pre> <i class="annotation" style="left: -52px;top: 92px;">1</i> <i class="annotation" style="left: -52px;top: 162px;">2</i> <code data-trim data-noescape data-line-numbers="7-9,18|10-17" style="max-height: 600px"> <script type="text/template"> public class LoanBatchSubmissionListener { @Autowired private ApplicationEventPublisher eventPublisher; @Autowired private DecisionService decisionService; ‎ @Async @EventListener(LoanBatchSubmitted.class) public void handleEvent(LoanBatchSubmitted loanBatchSubmission) { final List<Integer> results = decisionService.evaluateLoans(loanBatchSubmission.getLoanApplications()) .stream() .map(f -> (int) (f * 100)) .collect(Collectors.toList()); ‎ eventPublisher.publishEvent( new LoanBatchScored(this, loanBatchSubmission.getLoanApplications(), results) ); } } </script> </code> </pre> --- <h6 style="color: grey;text-transform: inherit">[ /service/DataBricksDecisionService.java ]</h6> <pre> <code data-trim data-noescape data-line-numbers="" style="max-height: 600px"> <script type="text/template"> public List<Float> evaluateLoans(List<LoanApplicationViewData> loanApplications) { // Map LoanApplication -> JSON structure and aggregate final List<LoanMLInput> mlLoanApplications = loanApplications .stream() .map(loanMapper::viewToMLInput) .collect(Collectors.toList()); ‎ final MLRequest request = new MLRequest(); request.setDataframeRecords(mlLoanApplications); ‎ final MLResponse modelResults = restTemplate.postForObject( databricksIntegrationProperties.getEndpointUrl(), request, MLResponse.class); ‎ // Update loans with acceptance chance value if (null == modelResults) { return new ArrayList<>(); } ‎ return modelResults.getPredictions(); } </script> </code> </pre> </div> <div class="col"> <blockquote class="annotation" data-number="1"> The <strong>@Async</strong> annotation makes this bean execute in a separate thread.<br/><br/> The <strong>@EventListener</strong> annotation allows us to listen and execute anytime a specified event is received. </blockquote> <blockquote class="annotation" data-number="2"> When the `LoanBatchSubmitted` event is handled, we use the <strong>`decisionService`</strong> to evaluate each of the loans and score its approval probability.<br/><br/> We then raise a new event, `LoanBatchScored` with the approval predictions. </blockquote> </div> </div> </div> ___ # Data Flow <!-- .slide: class="multi-columns wide" --> <img src="/images/presentations/microservices/microservice-events-stage2.png" /> Note: We've seen how we can raise an event, and then listen for and process an event in the background. Now let's use this in practice to add an intelligent feature to our application. When a loan is scored, we want to be able to automatically reject the loan if it doesn't meet our configured threshold. ___ # Loan Decision Automation <!-- .slide: class="multi-columns wide" --> <div class="container"> <div class="row"> <div class="col col-7"> <h6 style="color: grey;text-transform: inherit">[ /events/LoanBatchScoreDecisionThresholdListener.java ]</h6> <pre> <i class="annotation" style="left: -52px;top: 32px;">1</i> <i class="annotation" style="left: -52px;top: 102px;">2</i> <i class="annotation" style="left: -52px;top: 142px;">3</i> <i class="annotation" style="left: -52px;top: 252px;">4</i> <code data-trim data-noescape data-line-numbers="2-6|8-10,30|11-12|14-25" style="max-height: 600px"> <script type="text/template"> public class LoanBatchScoreDecisionThresholdListener { @Autowired private ApplicationEventPublisher eventPublisher; ‎ @Autowired private LoanDecisionProperties loanDecisionProperties; ‎ @Async @EventListener(LoanBatchScored.class) public void handleEvent(LoanBatchScored loanBatchScored) { final List<LoanApplicationViewData> loanApplications = loanBatchScored.getLoanApplications(); final List<Integer> confidenceScores = loanBatchScored.getConfidenceScores(); ‎ IntStream.range(0, loanApplications.size()) .forEach(i -> { final LoanApplicationViewData currentLoanApplication = loanApplications.get(i); ‎ if (confidenceScores.get(i) < loanDecisionProperties.getRejectionThreshold()) { ‎ // here we need to record a decision, and ensure this system // automatically reconciles that decision with other dependent applications // [ missing code ] ‎ } }); } } </script> </code> </pre> </div> <div class="col"> <blockquote class="annotation" data-number="1"> <strong>@Autowired</strong> dependencies we have injected. <br/> The <strong>`ApplicationEventPublisher`</strong> allows us to publish events, and the <strong>`LoanDecisionProperties`</strong> represents a set of configuration where we have specified what our acceptance threshhold is. </blockquote> <blockquote class="annotation" data-number="2"> We listen for a <strong>`LoanBatchScored`</strong> event. </blockquote> <blockquote class="annotation" data-number="3"> We get the loans that had been scored from the event, and get the confidence threshold from our configuration object. </blockquote> <blockquote class="annotation" data-number="3"> For each of the loans, if the predicted score is less than the configured threshold, we need to raise events indicating that loan has been rejected. </blockquote> </div> </div> </div> ___ # Loan Decision Automation <!-- .slide: class="multi-columns wide" --> <div class="container"> <div class="row"> <div class="col col-7"> <h6 style="color: grey;text-transform: inherit">[ /events/LoanBatchScoreDecisionThresholdListener.java ]</h6> <pre> <i class="annotation" style="left: -52px;top: 320px;">1</i> <code data-trim data-noescape data-line-numbers="20-26" style="max-height: 600px"> <script type="text/template"> public class LoanBatchScoreDecisionThresholdListener { @Autowired private ApplicationEventPublisher eventPublisher; ‎ @Autowired private LoanDecisionProperties loanDecisionProperties; ‎ @Async @EventListener(LoanBatchScored.class) public void handleEvent(LoanBatchScored loanBatchScored) { final List<LoanApplicationViewData> loanApplications = loanBatchScored.getLoanApplications(); final List<Integer> confidenceScores = loanBatchScored.getConfidenceScores(); ‎ IntStream.range(0, loanApplications.size()) .forEach(i -> { final LoanApplicationViewData currentLoanApplication = loanApplications.get(i); ‎ if (confidenceScores.get(i) < loanDecisionProperties.getRejectionThreshold()) { ‎ eventPublisher.publishEvent( new PropagateLoanDecision(this, currentLoanApplication, LoanDecisionStatus.REJECTED) ); ‎ eventPublisher.publishEvent( new RecordLoanDecision(this, currentLoanApplication, LoanDecisionStatus.REJECTED) ); ‎ } } ); } } </script> </code> </pre> </div> <div class="col"> <blockquote class="annotation" data-number="1"> Using our <strong>`ApplicationEventPublisher`</strong> we raise two events.<br/><br/> The <strong>`PropagateLoanDecision`</strong> event allows us to asynchronously inform external systems of our update The <strong>`RecordLoanDecision`</strong> event allows us to asynchronously record a status (REJECTION)<br/><br/> </blockquote> </div> </div> </div> ___ # Data Flow <!-- .slide: class="multi-columns wide" --> <img src="/images/presentations/microservices/microservice-events-stage3.png" /> Note: Now that we've handled intelligent application functionality using events, let's take another look at how we trigger this functionality when a user interacts with a REST endpoint. ___ # Executing our Tests <div class="container"> <div class="row"> <div class="col col-8"> <img src="/images/presentations/microservices/codespaces/tests.png" style="width: 100%; height: 550px; object-fit: none; object-position: 0 0"/> </div> <div class="col"> <blockquote class="annotation" data-number="1"> Run your tests again. </blockquote> <blockquote> Validate all scenarios now pass. With all tests passing, we can now be sure our application is functioning as expected. </blockquote> </div> </div> </div> --- # Putting it all Together <!-- .slide: data-background-image="/images/presentations/ppt-background.png" --> ___ # Running your Microservice <div class="container"> <div class="row"> <div class="col col-8"> <img src="/images/presentations/microservices/codespaces/import-java-project.png"/> <img src="/images/presentations/microservices/codespaces/rebuild-all.png" style="width: 100%; height: 150px; object-fit: none; object-position: 0 0"/> <img src="/images/presentations/microservices/codespaces/debug.png" style="width: 100%; height: 175px; object-fit: none; object-position: -15px -75px"/> </div> <div class="col"> <blockquote class="annotation" data-number="1"> Ensure your Java project is imported. </blockquote> <blockquote class="annotation" data-number="2"> Rebuild your Java project. </blockquote> <blockquote class="annotation" data-number="3"> Debug your microservice. This starts your microservice, and attaches a debugger so you can set breakpoints. </blockquote> </div> </div> </div> ___ # Exposing your Microservice <div class="container"> <div class="row"> <div class="col col-8"> <img src="/images/presentations/microservices/codespaces/port-visibility-changes.png"/> <br/>---<br/> <img src="/images/presentations/microservices/codespaces/port-visibility-final.png"/> </div> <div class="col"> <blockquote class="annotation" data-number="1"> Modify the following ports <br/>to be <strong>`public`</strong>:<br/> <br/> - `Extension UX (3000)` <br/> - `Extension Application (8080)` </blockquote> </div> </div> </div> ___ # Creating an FFDC App <!-- .slide: class="wide" --> 1. Navigate to https://developer.preprod.fusionfabric.cloud/ 1. Sign in with your provisioned 'TechCon' Credentials > <strong>username:</strong><br/> > <i style="color: blue">[first part of your Finastra email]</i>@finastratechcon.onmicrosoft.com <br/> > > <i>ex: mike.lucas@finastratechcon.onmicrosoft.com</i> > > <strong>password:</strong><br/> > Innovate@TechCon 1. Change your password on first login ___ # Developer Portal <img src="/images/presentations/microservices/ffdc/ffdc-apps.png"/> <i class="fa-solid fa-angles-right"></i> <img src="/images/presentations/microservices/ffdc/register-app.png" /> ___ # Create an App <div class="container"> <div class="row"> <div class="col col-8"> <img src="/images/presentations/microservices/ffdc/ffdc-setup-app-name.png" style="width:1000px"/> </div> <div class="col"> <blockquote class="annotation" data-number="1"> Enter your application name </blockquote> <blockquote class="annotation" data-number="2"> Click `Next` </blockquote> </div> </div> </div> ___ # Create an App <div class="container"> <div class="row"> <div class="col col-8"> <img src="/images/presentations/microservices/ffdc/ffdc-setup-spi.png" style="width:1000px"/> </div> <div class="col"> <blockquote class="annotation" data-number="3"> Under the 'SPI' tab, choose the `TechCon - Decision Extension` SPI </blockquote> </div> </div> </div> ___ # SPI Base URL <div class="container"> <div class="row"> <div class="col col-8"> <img src="/images/presentations/microservices/ffdc/ffdc-setup-get-spi-endpoint.png" style="width:1000px"/> <img src="/images/presentations/microservices/ffdc/ffdc-setup-spi.png" style="width:1000px; height: 350px; object-fit: none; object-position: 0 0"/> </div> <div class="col"> <blockquote class="annotation" data-number="4"> Back in Codespaces, under the 'Ports' menu, right click the <br/><strong>`Extension Application (8080)`</strong> endpoint, and <strong>`Copy Local Address`</strong> </blockquote> <blockquote class="annotation" data-number="5"> Paste this value in the FFDC App configuration screen under the <strong>`SPI Base URL`</strong> form field. </blockquote> </div> </div> </div> ___ # Create an App <div class="container"> <div class="row"> <div class="col col-8"> <img src="/images/presentations/microservices/ffdc/ffdc-setup-register.png" style="width:1000px"/> </div> <div class="col"> <blockquote class="annotation" data-number="6"> Click `Next` </blockquote> <blockquote class="annotation" data-number="7"> Click `Register Application` </blockquote> </div> </div> </div> ___ # Register UX Endpoint <div class="container"> <div class="row"> <div class="col col-8"> <img src="/images/presentations/microservices/ffdc/ffdc-ux-config.png" style="width:1000px"/> </div> <div class="col"> <blockquote class="annotation" data-number="8"> Click `Add UX App` on main app screen </blockquote> <blockquote class="annotation" data-number="9"> Enter a name, description, and an icon URL <small>(example:<br/>https://www.iconpacks.net/icons/1/free-rocket-icon-1206-thumb.png)</small> </blockquote> <blockquote class="annotation" data-number="10"> Back in Codespaces, under the 'Ports' menu, right click the <br/><strong>`Extension UX (3000)`</strong> endpoint, and <strong>`Copy Local Address`</strong> </blockquote> <blockquote class="annotation" data-number="11"> Paste that address into the Web `URL` field under `URL Template` </blockquote> </div> </div> </div> ___ # End-to-End TechCon Workflow <!-- .slide: class="wide" --> 1. Navigate to the TechCon 'Monolith': https://techcon.preprod.fusionfabric.cloud/ 2. Sign-in with your provisioned 'TechCon' Credentials > <strong>username:</strong><br/> > <i style="color: blue">[first part of your Finastra email]</i>@finastratechcon.onmicrosoft.com > > <i>ex: mike.lucas@finastratechcon.onmicrosoft.com</i> > > <strong>password:</strong><br/> > (whatever you set it to) ___ # Configure the Monolith <div class="container"> <div class="row"> <div class="col col-8"> <img src="/images/presentations/microservices/ffdc/techcon-config.png" style="width: 1000px"/> </div> <div class="col"> <blockquote class="annotation" data-number="1"> Click the gear icon in the lower left side of the screen </blockquote> <blockquote class="annotation" data-number="2"> In the TechCon monolith configuration screen, select the FFDC app you created earlier from the dropdown. </blockquote> </div> </div> </div> ___ # Submitting Loans for Decisioning <div class="container"> <div class="row"> <div class="col col-8"> <img src="/images/presentations/microservices/ffdc/select-and-submit.png" style="width: 1000px"/> </div> <div class="col"> <blockquote class="annotation" data-number="1"> In select one or more loans to transfer to your extension app </blockquote> <blockquote class="annotation" data-number="2"> Click `Submit for Review` in the lower right of the screen. </blockquote> <blockquote class="annotation" data-number="3"> To launch your decision application, click `Open Decision Engine` in the lower right of the screen. </blockquote> </div> </div> </div> ___ # The Decisioning Dashboard <div class="container"> <div class="row"> <div class="col col-8"> <i class="annotation" style="left: 10px;top: 192px;">1</i> <i class="annotation" style="left: 710px;top: 192px;">2</i> <i class="annotation" style="left: 830px;top: 192px;">3</i> <img src="/images/presentations/microservices/ffdc/decisioning-dashboard.png" style="width: 1000px"/> </div> <div class="col"> <blockquote class="annotation" data-number="1"> Loans that have been submitted </blockquote> <blockquote class="annotation" data-number="2"> The predicted confidence of the loan being approved, using the ML model </blockquote> <blockquote class="annotation" data-number="3"> The manual or automated decision of whether the loan is approved </blockquote> </div> </div> </div> ___ # The Decisioning Dashboard <img src="/images/presentations/microservices/ffdc/loan-approval.png" style="width: 1000px"/> ___ # The Decisioning Dashboard <img src="/images/presentations/microservices/ffdc/decisioning-dashboard-approved.png" style="width: 1000px"/> --- # Thank you <!-- .slide: data-background-image="/images/presentations/ppt-background.png" -->