<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Roddy</title>
    <description>The latest articles on DEV Community by Roddy (@roddy).</description>
    <link>https://dev.to/roddy</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F630717%2F61ca4b42-31af-4a03-b9c7-9d558e55744e.png</url>
      <title>DEV Community: Roddy</title>
      <link>https://dev.to/roddy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/roddy"/>
    <language>en</language>
    <item>
      <title>Easy Spring-Boot with Drools</title>
      <dc:creator>Roddy</dc:creator>
      <pubDate>Fri, 08 Oct 2021 14:55:04 +0000</pubDate>
      <link>https://dev.to/roddy/easy-spring-boot-with-drools-2n7o</link>
      <guid>https://dev.to/roddy/easy-spring-boot-with-drools-2n7o</guid>
      <description>&lt;p&gt;There's a million of these articles and they're all overly complex. You can expose your Drools &lt;code&gt;KieContainer&lt;/code&gt; as a bean with 2 lines if you let Drools manage the rules on your classpath:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Bean&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;KieContainer&lt;/span&gt; &lt;span class="nf"&gt;kieContainer&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;KieServices&lt;/span&gt; &lt;span class="n"&gt;kieServices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;KieServices&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;kieServices&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getKieClasspathContainer&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Boom. Done. No need to futz with file I/O, the &lt;code&gt;KieFileSystem&lt;/code&gt;, or any of that other nonsense. Drools will do it all for you if you let it -- why make your life more complicated?&lt;/p&gt;




&lt;p&gt;For completeness, you'd use it in your components/services like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FooService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Inject the bean using constructor injection&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;KieContainer&lt;/span&gt; &lt;span class="n"&gt;kieContainer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;FooService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;KieContainer&lt;/span&gt; &lt;span class="n"&gt;kieContainer&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kieContainer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kieContainer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;fireRules&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;KieBase&lt;/span&gt; &lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kieContainer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getKieBase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"validaton"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;KieSession&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rules&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newKieSession&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;insert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// add facts into working memory&lt;/span&gt;
            &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fireAllRules&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dispose&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This all works if you have your rules on your classpath, with a kmodule.xml describing your kieBases in META-INF. &lt;/p&gt;

&lt;p&gt;If you want to see a working example, my &lt;a href="https://github.com/roddy/library-demo"&gt;library demo application&lt;/a&gt; is a Spring-Boot app I developed for my series of articles about how not to interact with databases.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cover image attribution: &lt;a href="https://pixabay.com/photos/white-paper-texture-background-1714170/"&gt;coyot @ PixaBay&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>spring</category>
      <category>springboot</category>
      <category>drools</category>
    </item>
    <item>
      <title>Behavior Driven Testing and Drools</title>
      <dc:creator>Roddy</dc:creator>
      <pubDate>Thu, 07 Oct 2021 05:52:51 +0000</pubDate>
      <link>https://dev.to/roddy/behavior-driven-testing-and-drools-2k36</link>
      <guid>https://dev.to/roddy/behavior-driven-testing-and-drools-2k36</guid>
      <description>&lt;p&gt;Behavior Driven Design (BDD) and Drools go together like chocolate and cayenne pepper. Your first reaction may be "blech!" but then you actually try it and it kind of grows on you like a fungus. It may not be your cup of cocoa, but it works and when you have a complex problem space, it may actually be an improvement in terms of programmer efficiency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Behavior Driven Design&lt;/strong&gt; is one of those hand-wavy terms that is hard to explain in depth. Basically it's a form of software development where your requirements are described by behavior -- the behavior of the user, the system, the widget, whatever. Here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;&lt;span class="nf"&gt;Given &lt;/span&gt;the user is on the login screen
&lt;span class="nf"&gt;When &lt;/span&gt;the user enters an incorrect password
&lt;span class="nf"&gt;Then &lt;/span&gt;the system should send an email
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This requirement (called a "spec" or "specification") describes a behavior (actor fails to login), the expected result (email is sent), and some preconditions (location is the login screen.) Specs are written in plain English (or other spoken language) rather than any sort of programming language or psuedo-code.&lt;/p&gt;

&lt;p&gt;BDD is closely related to Test Driven Design (TDD) in that the behavior spec that describes the requirements also describes the test. Before any coding can begin, the specs are prepared describing the behavioral expectations for the system. Then code is written to implement this, and finally we use the same specs to verify the expected behavior. It's rather straight-forward, yeah? It's just basically TDD except that instead of the unit test being the first thing that gets written, it's the human-readable description of the behavioral expectation of the system. &lt;/p&gt;

&lt;p&gt;The behavior spec defines both our test case and our requirements. What if we could just &lt;em&gt;run&lt;/em&gt; the spec like a unit test?&lt;/p&gt;

&lt;p&gt;Enter cucumber. (The technology, not the vegetable.)&lt;/p&gt;

&lt;h1&gt;
  
  
  Cucumbers, gherkins, and other pickles
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Cucumber&lt;/strong&gt; is a BDD testing framework, based around the idea that your spec &lt;em&gt;can&lt;/em&gt; both define the requirements and be the test to verify them. It does this by leveraging a language called &lt;em&gt;gherkin&lt;/em&gt;, which really is just a list of restricted keywords ("given", "when", "then", etc.) That example spec I showed previously for a failed login behavior? That's gherkin.&lt;/p&gt;

&lt;p&gt;It looks suspiciously like English, and that's the point. You don't need to know anything about code or programming to write a spec. (Gherkin can be internationalized as well. I've written behavioral specifications in Klingon just to prove it was possible. My manager laughed and made me rewrite it, of course.)&lt;/p&gt;

&lt;p&gt;I'm not going to go too much in depth into Cucumber and how it works. All you really need to know is that your spec is written in something a regular non-programmer person can read, and it describes some behavioral requirement for your application. Cucumber translates that "plain English" into actions that integrate into the testing framework of your choice, thus allowing you to use your requirements as the inputs for your unit or integration test.&lt;/p&gt;

&lt;h1&gt;
  
  
  Drooling over cucumbers
&lt;/h1&gt;

&lt;p&gt;Hopefully you already know that &lt;a href="https://www.drools.org/"&gt;Drools&lt;/a&gt; is a business rules management system. You write rules in either "drl" syntax, in spreadsheets, or in glorified flowcharts, and then let your application throw data at it.&lt;/p&gt;

&lt;p&gt;I'll be the first to jump on the "I love Drools!" bandwagon, but even I will admit that it is quite complicated. It's not something that you can drop entry level programmers into and expect them to just get; the framework is extremely powerful, but its abstractions are not always self-evident. If you print the &lt;a href="https://docs.drools.org/latestFinal/drools-docs/html_single/"&gt;documentation&lt;/a&gt; for the latest version of Drools (7.59 at time of writing), you'll get 616 &lt;em&gt;pages&lt;/em&gt; about the framework.&lt;/p&gt;

&lt;p&gt;This leaves us in a bit of a bind. Drools is supposed to model business logic in the form of rules, but to properly implement them you really need a programmer with a solid understanding of the framework. Your business analyst who understands the business may be able to write some simple or trivial rules, but they're also very likely to do it inefficiently. And for more complex rules, forget it. Your engineer, on the other hand, could write the rule -- but they don't have the necessary business knowledge to do so correctly.&lt;/p&gt;

&lt;p&gt;This is where Behavior Driven Design shows up to save the day. Your business analyst writes out the expected behavior in plain English (or another common spoken language.) Your engineer then implements that plain English requirement in Drools. And then, finally, we drop that plain English behavioral specification into Cucumber, and verify that the system does what the business analyst asked it to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  An anecdote
&lt;/h2&gt;

&lt;p&gt;Yes, I too was skeptical when this was first proposed to me. I was working in healthcare IT for a US-based startup. My application would calculate how much a patient should be charged for whatever-it-is that they were in the hospital for. This was an extremely complex calculation, which involved things like health insurance policies (sometimes multiple ones with varying coverage rules), the patient's recent medical history (especially how many visits/how much they'd paid so far against the plan), the contracted cost of the procedure, physician fees for specialists, various discounts, offsets from charitable donations based on credit score, and so on. Honestly, I understood very little of the business; I've only been to the hospital a handful of times, mostly as a visitor. But I did have a robust set of Drools rules that would magically spit out a reasonable-looking number after I tossed the patient's life history, current horoscope, and yesterday's winning lottery picks into working memory.&lt;/p&gt;

&lt;p&gt;And then the Affordable Care Act was passed (commonly called "Obamacare") and all of a sudden we had to update my rules. Now we had a problem. I had some very smart business analysts who understood exactly how we needed to calculate now. I had what was effectively a black box of rules that I could modify because I understood the Drools framework. And then we had a gaping chasm between us which basically represents the fact that we didn't really speak a common language. My analysts could talk about healthcare 'til the cows came home, but to me it sounded like the &lt;em&gt;wah wah wah&lt;/em&gt; from the Peanuts cartoons.&lt;/p&gt;

&lt;p&gt;So the analysts and I sat down and came up with a plan of action. Our first problem, we realized, is that while we had rules, they were effectively a black box. We had no way of knowing whether the numbers they were producing were accurate. Before we could determine how the rules had to change, we first had to understand how the rules worked today.&lt;/p&gt;

&lt;p&gt;Fair enough. The solution here is clearly to write tests to verify behavior based on known inputs. &lt;/p&gt;

&lt;p&gt;And this is where the eureka moment occurred. I, clearly, did not have the necessary business knowledge to prepare these test cases. The business analysts, on the other hand did -- but did not have the technical knowledge to implement the tests. So why not have them write gherkin test cases to validate the &lt;em&gt;behavior&lt;/em&gt; of the system.&lt;/p&gt;

&lt;p&gt;It was genius. After all, if a test failed in the future due to some changes, I could just take that plain English representation of a requirement back to the business analysts and say, "Hey, I implemented the XYZ use case for the ticket, but this other use case failed. Can you review?" And &lt;em&gt;they could&lt;/em&gt; review it, because the other use case was written in English and not some programmer mumbo jumbo. Huzzah!&lt;/p&gt;

&lt;h1&gt;
  
  
  Cucumber and you
&lt;/h1&gt;

&lt;p&gt;Healthcare is hard, and I don't work in that field anymore, so I can't exactly show you the sorts of rules I was dealing with there. Luckily coming up with toy examples for Drools questions is a particular hobby of mine, so we can still muddle through with an example.&lt;/p&gt;

&lt;p&gt;So let's say we're writing a game about space piracy. We've got space pirates, regular civilians, and the military all zooming around in their spaceships, hauling cargo of various kinds (some of which is illegal.) Oh and there's also aliens.&lt;/p&gt;

&lt;p&gt;Anyway, so we've got this game, and we've decided to implement our business logic in Drools. In this case our business logic will be stuff like validation (eg. is this procedurally-generated ship valid?) and also for calculations (eg. my ship is of type X, I'm at coordinates Y, and I want to go to coordinates Z ... can I?) For the sake of this question, we're going to consider the validation rules -- but if you're curious about the rest of it, I may have gotten a wee bit carried away implementing the &lt;a href="https://github.com/roddy/drools-and-cucumber"&gt;example application&lt;/a&gt; available on GitHub.&lt;/p&gt;

&lt;p&gt;Right. So, validation. Today we get a new requirement: we need to restrict how our ships are named. Luckily our Business Analyst or Product Owner has jumped aboard the BDD bandwagon and gives us our requirements in gherkin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;&lt;span class="kn"&gt;Scenario&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;An &lt;/span&gt;Alien spaceship cannot have a name starting with U.S.S
  &lt;span class="nf"&gt;When &lt;/span&gt;I have an Alien spaceship named &lt;span class="s"&gt;"U.S.S. Enterprise"&lt;/span&gt;
  &lt;span class="nf"&gt;Then &lt;/span&gt;my spaceship is not valid
  &lt;span class="err"&gt;And the error message should contain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;"only&lt;/span&gt; &lt;span class="err"&gt;hum&lt;/span&gt;&lt;span class="nf"&gt;an &lt;/span&gt;ships may use prefix U.S.S."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cool biz. It's a pretty simple requirement, so you can probably already imagine what the rule is going to look like, so we'll skip past that temporarily and instead talk about ... well how do I run this as a unit test?&lt;/p&gt;

&lt;p&gt;The answer: Cucumber. I think I mentioned that. Specifically, two cucumber libraries: &lt;code&gt;cucumber-java&lt;/code&gt; and &lt;code&gt;cucumber-junit&lt;/code&gt; (because I am firmly in the JUnit camp, but for reference I have used TestNG for Cucumber and Drools as well and the principles are the same.) &lt;/p&gt;

&lt;p&gt;For this example, we'll use the latest version of these two libraries: 6.10.4 at time of writing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.cucumber&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;cucumber-java&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;6.10.4&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.cucumber&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;cucumber-junit&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;6.10.4&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's important to note that Cucumber hasn't caught up with the modern age yet and is only compatible with JUnit 4, so if you're using JUnit 5 you'll need to include a dependency on &lt;code&gt;junit-vintage-engine&lt;/code&gt; and remember not to use &lt;em&gt;any&lt;/em&gt; JUnit 5 features at all in your tests. (Even your assertions need to be the ones in the old &lt;code&gt;junit.*&lt;/code&gt; package.)&lt;/p&gt;

&lt;h2&gt;
  
  
  The glue
&lt;/h2&gt;

&lt;p&gt;The next thing we do is write what is called the "glue". This is a class (or classes) which "glue" the gherkin to the application, hence the name. It basically provides a translation layer between the gherkin and actual functionality. In our case, for each of the "steps" (the lines prefixed "When", "Then", "Given", "And"), we need to provide a bit of parsing logic to translate that into something that feeds data into the application, does an action, or asserts something.&lt;/p&gt;

&lt;p&gt;Cucumber makes some useful annotations available, so the basic outline of our methods will look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SpaceshipValidationGlue&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@When&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"^I have an Alien spaceship named \"(.*)\"$"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setSpaceshipSpeciesAndName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// set the name of the spaceshp we're passing into the rules&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Then&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"^my spaceship is not valid$"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;assertInvalid&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// fire the rules (if needed) and assert the validity of the result&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Then&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"^the error message should contain: \"(.*)\"$"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;assertErrorMessageContains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// fire the rules (if needed) and verify the error message&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Basically, you have a method, annotated with one of the Cucumber &lt;code&gt;@When&lt;/code&gt;, &lt;code&gt;@Then&lt;/code&gt;, &lt;code&gt;@Given&lt;/code&gt;, etc. annotations. These annotations contain a regular expression, which you can use to extract variables. Then in the method you can do whatever-it-is that is being described by the English representation. Note that while Cucumber provides all of the reserved keywords as annotations -- both in English and a variety of other languages -- it doesn't really matter which one you use. There's no difference in using &lt;code&gt;@When&lt;/code&gt; versus &lt;code&gt;@Then&lt;/code&gt;. However I like to use &lt;code&gt;@When&lt;/code&gt; for all of the steps which do some sort of initialization, and &lt;code&gt;@Then&lt;/code&gt; for any which do assertions; that way I can just look at the annotation and known generally what that broad category that method belongs to. But you can do as you like.&lt;/p&gt;

&lt;p&gt;Now if you're trying to follow along in my GitHub repository, you'll notice that the step definitions in there are a lot more complex -- because I have a &lt;em&gt;lot&lt;/em&gt; more rules and a &lt;em&gt;lot&lt;/em&gt; more features. It was a surprisingly fun toy example to put together, and I got &lt;em&gt;totally&lt;/em&gt; carried away. I make no apologies, but it does mean that at least for this specific step definition you'll need to follow along here instead.&lt;/p&gt;

&lt;p&gt;Right. Back to our spaceship name validation. Let's go about implementing the step definitions for this use case.&lt;/p&gt;

&lt;p&gt;Usually I like to start from the top, but in this case we need to start from the bottom -- namely, what are we passing into the rules? In this case, we're passing in a &lt;code&gt;Spaceship&lt;/code&gt; object, so we'll need to add that to our class definition. Here's where we run into our first gotcha.&lt;/p&gt;

&lt;p&gt;For each test &lt;em&gt;suite&lt;/em&gt; (not individual test) the cucumber framework will new up an instance of this class. So since we can't pass our spaceship instance between individual methods, we'll need to save it as a class-level variable, and remember to "clear" it between individual Scenarios. (Gherkin Scenarios are analogous to test cases.) To do this, Cucumber gives us a &lt;code&gt;@Before&lt;/code&gt; annotation, called a "hook", so we can use that annotation to decorate a "setup" method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SpaceshipValidationGlue&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Spaceship&lt;/span&gt; &lt;span class="n"&gt;spaceshipUnderTest&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Before&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;spaceshipUnderTest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Spaceship&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Be careful with your imports! &lt;code&gt;@Before&lt;/code&gt; should be imported from &lt;code&gt;io.cucumber.java.Before&lt;/code&gt; -- there's an identically named JUnit 4 class which you &lt;em&gt;must not&lt;/em&gt; use.&lt;/p&gt;

&lt;p&gt;Anyway, now that we've got our spaceship defined, we can implement the &lt;code&gt;@When&lt;/code&gt; step definition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@When&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"^I have an Alien spaceship named \"(.*)\"$"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setSpaceshipSpeciesAndName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;spaceshipUnderTest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That takes care of our test setup. We've got two "Then" steps, which are the methods which validate the consequences of our action (our action being "we fired the validation rules.") So the first thing that has to happen is, clearly, that we need to fire the rules.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Then&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"^my spaceship is not valid$"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;assertInvalid&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fireRules&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// TODO validate the results&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;span class="nd"&gt;@Then&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"^the error message should contain: \"(.*)\"$"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;assertErrorMessageContains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fireRules&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// TODO verify the error message&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;fireRules&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;KieServices&lt;/span&gt; &lt;span class="n"&gt;kieServices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;KieServices&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;KieContainer&lt;/span&gt; &lt;span class="n"&gt;kContainer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kieServices&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getKieClasspathContainer&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;KieBase&lt;/span&gt; &lt;span class="n"&gt;kBase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kContainer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getKieBase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"validation"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;KieSession&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kBase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newKieSession&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;insert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spaceshipUnderTest&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fireAllRules&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dispose&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But wait! Why are we firing the rules twice?&lt;/p&gt;

&lt;p&gt;Good question. We shouldn't be. We should instead track the fact that we fired the rules already, and not fire them again and just reuse the same results for subsequent assertions. I like to use this with an &lt;code&gt;AtomicBoolean&lt;/code&gt; tracking variable that gets reset in the &lt;code&gt;@Before&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SpaceshipValidationGlue&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;AtomicBoolean&lt;/span&gt; &lt;span class="n"&gt;isRulesFired&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AtomicBoolean&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nd"&gt;@Before&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isRulesFired&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// ...&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;fireRules&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isRulesFired&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compareAndSet&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;KieServices&lt;/span&gt; &lt;span class="n"&gt;kieServices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;KieServices&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="nc"&gt;KieContainer&lt;/span&gt; &lt;span class="n"&gt;kContainer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kieServices&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getKieClasspathContainer&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="nc"&gt;KieBase&lt;/span&gt; &lt;span class="n"&gt;kBase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kContainer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getKieBase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"validation"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="nc"&gt;KieSession&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kBase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newKieSession&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;insert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spaceshipUnderTest&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fireAllRules&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dispose&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're getting close. Isn't this exciting?&lt;/p&gt;

&lt;p&gt;Next thing we need to do is get the results out of the rules, so we can assert against something in our steps. I'm going to take the easy way out and use a global object called &lt;code&gt;ValidationResult&lt;/code&gt;, but there's a number of ways we could do this instead. (Eg. we could pass the result object into working memory, we could have a "valid" flag on the spaceship itself, etc.) &lt;/p&gt;

&lt;p&gt;Since we're going to have to share the results across potentially multiple methods doing assertions, we'll need to store the results somewhere that's accessible to all methods in this class -- namely as a class variable. So we'll just drop it alongside the &lt;code&gt;Spaceship&lt;/code&gt; variable, and also update the &lt;code&gt;@Before&lt;/code&gt; to reset the value between scenarios.&lt;/p&gt;

&lt;p&gt;Thus, our completed step definitions look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SpaceshipValidationGlue&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;AtomicBoolean&lt;/span&gt; &lt;span class="n"&gt;isRulesFired&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AtomicBoolean&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Spaceship&lt;/span&gt; &lt;span class="n"&gt;spaceshipUnderTest&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;ValidationResult&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Before&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isRulesFired&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;spaceshipUnderTest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Spaceship&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;


    &lt;span class="nd"&gt;@When&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"^I have an Alien spaceship named \"(.*)\"$"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setSpaceshipSpeciesAndName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;spaceshipUnderTest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Then&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"^my spaceship is not valid$"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;assertInvalid&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fireRules&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;assertFalse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isValid&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Then&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"^the error message should contain: \"(.*)\"$"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;assertErrorMessageContains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fireRules&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;errorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getError&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;assertNotNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errorMessage&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errorMessage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;fireRules&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isRulesFired&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compareAndSet&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ValidationResult&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

            &lt;span class="nc"&gt;KieServices&lt;/span&gt; &lt;span class="n"&gt;kieServices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;KieServices&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="nc"&gt;KieContainer&lt;/span&gt; &lt;span class="n"&gt;kContainer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kieServices&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getKieClasspathContainer&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="nc"&gt;KieBase&lt;/span&gt; &lt;span class="n"&gt;kBase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kContainer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getKieBase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"validation"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="nc"&gt;KieSession&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kBase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newKieSession&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;insert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spaceshipUnderTest&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setGlobal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"validation"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fireAllRules&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dispose&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;assertNotNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As an aside, one of the cool things about these step definitions is that they're reusable. I can now include &lt;code&gt;I have a spaceship named "foo"&lt;/code&gt; in any of my scenarios, and this step definition will provide the implementation for it. IDEs like IntelliJ's IDEA provide built-in support for Gherkin and will automatically map from the gherkin feature to the defined step so you can navigate between them. (Note that this might be a paid feature in IntelliJ; I'm unfamiliar with other IDEs that may or may not support this functionality as well.)&lt;/p&gt;

&lt;h2&gt;
  
  
  The test runner
&lt;/h2&gt;

&lt;p&gt;Step definitions by themselves aren't tests though. They're just the translation layer, the glue. We still need the actual test runner.&lt;/p&gt;

&lt;p&gt;I usually go through these examples stepwise, but for the runner it's easier if I just show you the whole thing. This is the test runner for this example feature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.cucumber.junit.Cucumber&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.cucumber.junit.CucumberOptions&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.junit.runner.RunWith&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@RunWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Cucumber&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@CucumberOptions&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"html:target/cucumber_html/spaceshipValidation/"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                            &lt;span class="s"&gt;"json:target/json-spaceshipValidation.json"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                            &lt;span class="s"&gt;"junit:target/junit-spaceshipValidation.xml"&lt;/span&gt;&lt;span class="o"&gt;},&lt;/span&gt;
                 &lt;span class="n"&gt;glue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"app.roddy.space.validation.spaceship"&lt;/span&gt;&lt;span class="o"&gt;},&lt;/span&gt;
                 &lt;span class="n"&gt;features&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"src/test/resources/features/validation/spaceshipValidation.feature"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                 &lt;span class="n"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"@validation"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SpaceshipValidationRulesTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you're writing Cucumber tests in Java, you'll end up with a lot of these test runners, and they'll end up being primarily copy-paste jobs. There's a lot of boilerplate, but not a good way of extracing the commonalities into something less verbose.&lt;/p&gt;

&lt;p&gt;To start with, the &lt;code&gt;@RunWith&lt;/code&gt; annotation is the JUnit4 extension which identifies &lt;code&gt;Cucumber&lt;/code&gt; as the test runner. Then &lt;code&gt;@CucumberOptions&lt;/code&gt; configures this particular test suite as follows:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;plugin&lt;/td&gt;
&lt;td&gt;These plugins configure how the test outputs its results. HTML generates a webpage with test results. JSON spits out json. JUnit is JUnit xml, commonly used as an input for external reporters (eg Jenkins plugins)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;glue&lt;/td&gt;
&lt;td&gt;An array of packages where our glue file(s) live. This is the package for the step definition file we just wrote for our example feature.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;features&lt;/td&gt;
&lt;td&gt;The full path to the feature file. This isn't relative to the class path (src/test/resources), but from the project root.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tags&lt;/td&gt;
&lt;td&gt;Not really discussed here, but you can put annotations on your scenarios to categorize them so that you can target them specifically. A common workflow is to tag stuff &lt;code&gt;@wip&lt;/code&gt; or &lt;code&gt;@skip&lt;/code&gt; and exclude them from this parameter (eg. &lt;code&gt;~@wip&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You'll notice that the file itself is empty. If you have some sort of common setup/tear down steps, this is where you'd put that logic using the &lt;strong&gt;JUnit&lt;/strong&gt; &lt;code&gt;@Before&lt;/code&gt; and &lt;code&gt;@BeforeAll&lt;/code&gt; annotations (or "after" equivalents). An important thing to remember is that JUnit does properly identify each individual Scenario as a separate JUnit test; IDEs like IntelliJ IDEA are smart enough to understand this, but the JUnit framework itself just sees it as a single black-box thing it's running. So anything that you put in this file will run before &lt;em&gt;all&lt;/em&gt; of the scenarios or after &lt;em&gt;all&lt;/em&gt; of the scenarios.&lt;/p&gt;

&lt;p&gt;At my previous company, when I wrote Drools for a healthcare application, I developed a code-coverage reporting framework for Drools. It required attaching some listeners to the Drools session and collocating the metrics for the suite, and this is where I implemented that sort of logic. Otherwise you could put some common setup/teardown in here as well. You might've noticed that we load the rules into memory every time we call &lt;code&gt;fireRules()&lt;/code&gt; in the step definitions; we could improve performance by moving that "load" logic here so the rules are only loaded once.&lt;/p&gt;

&lt;p&gt;At this point, we're actually &lt;em&gt;done&lt;/em&gt; with our unit tests. You can run &lt;code&gt;SpaceshipValidationRulesTest&lt;/code&gt; as a JUnit test, and it will actually track down that gherkin Scenario and run it using your glue. The test will fail, of course, since we've not written the rule yet -- but hey that's test driven development for you. Huzzah!&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule
&lt;/h2&gt;

&lt;p&gt;The rule is pretty anti-climactic at this point. I intentionally chose a very simple rule with a very simple spec as an example, and as a result it's actually not very interesting in terms of implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;global ValidationResult validation;

rule "Only human spaceships can use the prefix U.S.S."
when
  Spaceship( name != null,
             name str[startsWith] "U.S.S.",
             belongsTo != Species.HUMAN)
then
  validation.setIsValid(false);
  validation.appendMessage("only human ships may use prefix U.S.S.");
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just like it says on the tin. If the spaceship is not a Human ship, and the name starts with "U.S.S.", then we reject this as not being a valid spaceship.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;And there you have it. We have a complex system, a requirement written in plain English that can be run as a test, and a rule implemented against it. Clearly most real world applications won't involve spaceship, aliens, and piracy, but hopefully you can imagine how this might work with a legitimate business use case that requires in-depth knowledge. &lt;/p&gt;

&lt;p&gt;Healthcare, banking, accounting, HR -- there's a lot of very complicated businesses which could benefit from business rules, but where it would be a waste of time (and effort) to try and educate your programmers to be subject matter experts. Better to let your SMEs and product owners describe the expected behavior in a way they understand, and let the programmers implement the system using their own expertise, and let the Cucumber keep both sides honest (and accurate.)&lt;/p&gt;

&lt;p&gt;It's also worth noting that Cucumber isn't just for Java, and it's not just for unit tests. At the unit test level, it makes sense to implement tests with Java because a Drools application will be written in Java, by definition. But you can also design an integration or end-to-end testing framework that runs independently, and use other languages for that. Cucumber was originally written in Ruby; the healthcare application I've mentioned a few times had its e2e tests written in Cucumber and Ruby. There's also Javascript libraries, C#, a much maligned Python implementation, and so on. I've only shown you here the tip of the proverbial iceberg, and focused on how you can validate your Drools business logic, but the reality is that this is a very powerful tool and there are many more use cases which may be of use to you.&lt;/p&gt;

&lt;h1&gt;
  
  
  More information
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cucumber.io/"&gt;Cucumber&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.drools.org/"&gt;Drools&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/roddy/drools-and-cucumber"&gt;GitHub repository&lt;/a&gt; for this post.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Cover image attribution: &lt;a href="https://pixabay.com/photos/cucumbers-garden-harvest-1588945/"&gt;congerdesign @ pixabay&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>drools</category>
      <category>bdd</category>
      <category>cucumber</category>
    </item>
    <item>
      <title>Drools &amp; Databases, Part 3: The Solution</title>
      <dc:creator>Roddy</dc:creator>
      <pubDate>Sun, 26 Sep 2021 23:24:21 +0000</pubDate>
      <link>https://dev.to/roddy/drools-databases-part-3-the-solution-3j8g</link>
      <guid>https://dev.to/roddy/drools-databases-part-3-the-solution-3j8g</guid>
      <description>&lt;p&gt;In the third and last part of this extended rant about how &lt;em&gt;not&lt;/em&gt; to design database and rules interactions, I will describe how you should actually go about doing this.&lt;/p&gt;

&lt;p&gt;If you're new to the party, the first two parts of this discussion can be found here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/roddy/drools-databases-part-1-don-t-call-the-db-from-the-drl-3hg3"&gt;Part 1: Don't Call the DB From the DRL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/roddy/drools-databases-part-2-don-t-call-the-dao-from-the-drl-8c6"&gt;Part 2: Don't Call the DAO From the DRL&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you don't want to spend half your day reading, I'll summarize the salient points here. &lt;/p&gt;

&lt;p&gt;One of the most common questions on StackOverflow in the &lt;a href="https://stackoverflow.com/questions/tagged/drools" rel="noopener noreferrer"&gt;Drools tag&lt;/a&gt; is something along the lines of "how do I call my database from my &lt;a href="https://drools.org/" rel="noopener noreferrer"&gt;rules&lt;/a&gt;?"&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;part 1&lt;/strong&gt;, I explained why you shouldn't try to interact with the database directly from your rules (DRL or otherwise.) Safely interacting with a database using a JDBC driver (or library) is incredibly involved and takes significant effort to do safely and properly, especially in a production environment. It's just about impossible to properly manage transactions, connections (with or without pooling), prepared statements, result sets, and so on within the confines of a DRL file. I'm not even sure it's possible to attempt in any sane fashion in a decision table....&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;part 2&lt;/strong&gt;, I talked about why even interacting with DAOs should be avoided. A well-design data abstraction layer would mean that we don't need to worry about things like connection pooling and transaction management, so &lt;em&gt;in theory&lt;/em&gt; we could just interact with the DAOs and we'd be fine, right? Technically, yes, you could -- but the danger here becomes that you need to have extensive knowledge of how the Drools lifecycle works, along with how your data models are coupled (especially if you use hibernate's lazy loading.) This creates a significant issue for future maintenance, since it's not possible to test for the problems that you might introduce due to lack of knowledge in these areas -- such as data inconsistency arising from race conditions.&lt;/p&gt;

&lt;p&gt;Now, in &lt;strong&gt;part 3&lt;/strong&gt;, I finally get around to explaining what you &lt;em&gt;should&lt;/em&gt; do instead. ("Finally!" you say.)&lt;/p&gt;

&lt;h2&gt;
  
  
  The cop-out
&lt;/h2&gt;

&lt;p&gt;The answer you've all been waiting for is .... &lt;strong&gt;it depends.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No really. It depends on what your rules are actually doing and your problem space. But luckily there's a general rule of thumb which is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Interact with the database before you call the rules to get your data and pass it into working memory. Interact with the database after you call the rules to persist your results.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There's still problems here and I'll call them out, but we'll be wading into treacherous waters. Just put a bunch of DBAs into a room, ask them if we should be storing calculated or derived data in the database, and duck for cover.&lt;/p&gt;

&lt;h2&gt;
  
  
  The details
&lt;/h2&gt;

&lt;p&gt;Let's start with an example, because I like talking about actual code instead of waving my hands around and talking theory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario: the library
&lt;/h3&gt;

&lt;p&gt;Here's the situation we're going to be coding against. Our client is a &lt;a href="https://en.wikipedia.org/wiki/Library" rel="noopener noreferrer"&gt;library&lt;/a&gt; (with &lt;a href="https://en.wikipedia.org/wiki/Book" rel="noopener noreferrer"&gt;books&lt;/a&gt; in it; link is to Wikipedia for those unfamiliar with the concepts.) Our application tracks users who borrow and return books. A user is allowed to borrow up to 3 books at a time. Each book is allowed to be borrowed for a set amount of time (1 week, rounded to the nearest day). If the user has any books that are overdue, they are not allowed to borrow any new books until they have returned the overdue book(s).&lt;/p&gt;

&lt;p&gt;The library has a simple database that models books and people. The person table has an id (primary key), and some information about the person borrowing the book. The book table has an id (primary key), some information about the book itself, and a &lt;code&gt;borrowed_by&lt;/code&gt; field which is a foreign key reference to the person table's &lt;code&gt;id&lt;/code&gt; field. So when a book is "borrowed", the &lt;code&gt;borrowed_by&lt;/code&gt; field is set to the borrower's id. The &lt;code&gt;borrowed_on&lt;/code&gt; field indicates when this event occurred.&lt;/p&gt;

&lt;p&gt;Pretty simple. For the graphically oriented, here's the relationship diagram:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvnobcxfhlaroiriauvrt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvnobcxfhlaroiriauvrt.png" alt="Relationship diagram for the library database"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Diagram made in &lt;a href="https://dbdiagram.io/" rel="noopener noreferrer"&gt;DbDiagram&lt;/a&gt;, a pretty sweet and free online tool for this stuff.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you prefer looking at a complete, working application, the code from this post is available on GitHub &lt;a href="https://github.com/roddy/library-demo" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The application
&lt;/h3&gt;

&lt;p&gt;Our application is going to be handling &lt;code&gt;BookEvent&lt;/code&gt;s. These events come from an external system (the barcode readers used by the librarians to scan books that are being borrowed or returned.) The event arrives at our application looking like this simple model:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

&lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;BookEventType&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="no"&gt;BORROW&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;RETURN&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookEvent&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;BookEventType&lt;/span&gt; &lt;span class="n"&gt;eventType&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// required&lt;/span&gt;
    &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;bookId&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// required&lt;/span&gt;
    &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// optional&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Notice that &lt;code&gt;userId&lt;/code&gt; is optional. When a book is returned, we don't actually care who is returning it -- maybe it was tossed into a chute on the outside of the building after hours and gets scanned when the librarians arrive the following day. Maybe someone found the book on the bus and is returning it out of good will. It doesn't really matter, from anyone's perspective, who actually does the return. But for a 'borrow' event we do need to know it.&lt;/p&gt;

&lt;p&gt;When we receive a &lt;code&gt;RETURN&lt;/code&gt; BookEvent, we need to process it and update the appropriate tables as needed; this method should generally always return an "OK"/success -- situations like "this is not a library book" or "the returned book is damaged" are out of scope for this exercise. &lt;/p&gt;

&lt;p&gt;When we receive a &lt;code&gt;BORROW&lt;/code&gt; BookEvent, we need to return an indicator that says either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No, the user cannot borrow this book.&lt;/li&gt;
&lt;li&gt;Yes, the user has now successfully borrowed this book.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The "Yes"/success workflow should actually update the database and underlying system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Calling the rules
&lt;/h3&gt;

&lt;p&gt;At this point, we have enough information to start coding. First, we need to write a method that will take the received &lt;code&gt;BookEvent&lt;/code&gt; and call the rules.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

&lt;span class="cm"&gt;/**
 *  Process the book event and return an indication of success or failure.
 *
 * @param  event the event being processed
 * @return       true if the event is successful, false otherwise
 */&lt;/span&gt;
 &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;processEvent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BookEvent&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// TODO&lt;/span&gt;
 &lt;span class="o"&gt;}&lt;/span&gt; 


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, this is the part where many people will go to StackOverflow and start asking about how to interact with the database fromthe rules. Their first instinct is, of course, to just pass the &lt;code&gt;BookEvent&lt;/code&gt; to the rules and let it sort itself out.&lt;/p&gt;

&lt;p&gt;That's the wrong way to go about it, however. What we should do instead is first get the data we need out of the database, and &lt;em&gt;then&lt;/em&gt; call the rules.&lt;/p&gt;

&lt;h4&gt;
  
  
  Slight detour: the data
&lt;/h4&gt;

&lt;p&gt;What I like to do at this point is take a minute to think about my rules and mentally design my input objects. I want to make sure that the data I pass into my rules is sufficient, and is organized in a way that that is easily accessible. The easiest way to do this, I find, it to describe my rules in plain English, and describe the data I need to have in order for it to work.&lt;/p&gt;

&lt;p&gt;In our current scenario we have the following rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the person has 3+ books already checked out, a BORROW is not allowed&lt;/li&gt;
&lt;li&gt;If the person has any overdue book checked out, a BORROW is not allowed&lt;/li&gt;
&lt;li&gt;If the person is RETURNing a book, it is allowed&lt;/li&gt;
&lt;li&gt;If the person has &amp;lt; 3 books checked out, and none are overdue, the BORROW is allowed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And an error case, just to make things interesting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the book is already checked out by this user, a BORROW is not allowed &lt;em&gt;(maybe this was an accidental duplicate request)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also an error case because of how our &lt;code&gt;BookEvent&lt;/code&gt; is modelled:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the BORROW request has no associated person, it is not allowed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Looking at these rules we need the following information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The event type (BORROW or RETURN)&lt;/li&gt;
&lt;li&gt;The id of the book being borrowed&lt;/li&gt;
&lt;li&gt;The person, if known

&lt;ul&gt;
&lt;li&gt;All books currently checked out by this person&lt;/li&gt;
&lt;li&gt;For eached checked out book, the datetime it was checked out&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Now that we know the data we need, we can model the data we're going to pass into the rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We'll pass in the &lt;code&gt;BookEventType&lt;/code&gt; as-is&lt;/li&gt;
&lt;li&gt;We need the Book we're trying to check out -- id at minimum&lt;/li&gt;
&lt;li&gt;We'll pass in a &lt;code&gt;Person&lt;/code&gt; instance, so we can identify when they're missing from the request for the error case&lt;/li&gt;
&lt;li&gt;We'll need to pass in a &lt;code&gt;CheckedOutBook&lt;/code&gt; model that indicates when the book was checked out&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can model this as follows:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CheckedOutBook&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="nc"&gt;OffsetDateTime&lt;/span&gt; &lt;span class="n"&gt;checkedOutOn&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CheckedOutBook&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;checkedOutBooks&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now we're good to go. Our next step is, of course, getting our data out of the database and creating our inputs&lt;/p&gt;

&lt;h4&gt;
  
  
  Preparing our rule inputs
&lt;/h4&gt;

&lt;p&gt;For this example, we'll assume that we've already got a proper abstraction layer set up (Spring, Hibernate, whatever.) So we'll just get the data out of the database using some offscreen data services that will conveniently return the data data we need.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

&lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="nf"&gt;getUserFromEvent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BookEvent&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;userFromDb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dataService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUserById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUserId&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="n"&gt;userFromDb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Convert all Book (db model) into CheckedOutBook (rules model)&lt;/span&gt;
  &lt;span class="c1"&gt;// and save to Person&lt;/span&gt;
  &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setCheckedOutBooks&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;userFromDb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBooks&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
              &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
              &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                  &lt;span class="nc"&gt;CheckedOutBook&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CheckedOutBook&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
                  &lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
                  &lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setCheckedOutOn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBorrowedOn&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
                  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
              &lt;span class="o"&gt;}).&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And now all that's left is to actually call the rules:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

&lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;processEvent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BookEvent&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// First, get the necessary data from the database&lt;/span&gt;
    &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getUserFromEvent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Call the rules&lt;/span&gt;
    &lt;span class="nc"&gt;KieServices&lt;/span&gt; &lt;span class="n"&gt;kieServices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;KieServices&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;KieContainer&lt;/span&gt; &lt;span class="n"&gt;kContainer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kieServices&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getKieClasspathContainer&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;KieBase&lt;/span&gt; &lt;span class="n"&gt;kBase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kContainer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getKieBase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kbaseName&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nc"&gt;KieSession&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kBase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newKieSession&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;insert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; 
    &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;insert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; 
    &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fireAllRules&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// TODO -- update the database and return the result&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;But wait, what's this? We're inserting the event instance?&lt;/p&gt;

&lt;p&gt;We need two pieces of data from the event -- the type and the id of the book being borrowed. It makes more sense to pass them into the rules as part of the event instead of as free floating items. I've never been a fan of passing just Strings or UUIDs or Integers by themselves into working memory because there's no indication of what they actually &lt;em&gt;are&lt;/em&gt; -- they're just random pieces of data who have lost any semantics they might've once had associated with them when they had a variable name.&lt;/p&gt;

&lt;p&gt;Notice also that we've still got a pretty big &lt;code&gt;TODO&lt;/code&gt; left in this method -- we haven't designed ourselves a way to get the actual results out of these rules. We'll address that in the next section, when we write the rules.&lt;/p&gt;

&lt;h4&gt;
  
  
  The rules
&lt;/h4&gt;

&lt;p&gt;OK now for the fun part.&lt;/p&gt;

&lt;p&gt;We'll start with the easy bit, the &lt;code&gt;RETURN&lt;/code&gt; type:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

rule "Book is returned"
when
  BookEvent( type == BookEventType.RETURN )
then
  // TODO this is ok / successful
end


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;... Well that was boring. Now for the "error" cases:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

rule "Book is already checked out by this person"
when
  BookEvent( type == BookEventType.BORROW,
             $id: bookId )
  Person( $books: checkedOutBooks )

  exists( CheckedOutBook( id == $id ) from $books )
then
  // TODO this is not ok
end

rule "Unknown person"
when
  BookEvent( type == BookEventType.BORROW )
  not( Person() )
then
  // TODO this is not ok
end


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And finally, the actual meat-and-potatoes rules:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

rule "Person has 3+ existing checked out books"
when
  BookEvent( type == BookEventType.BORROW )
  Person( checkedOutBooks.size &amp;gt;= 3 )
then
  // TODO this is not ok
end

rule "Person has an overdue book"
when
  BookEvent( type == BookEventType.BORROW )
  Person( $books: checkedOutBooks )

  $checkoutLimit: OffsetDateTime() from OffsetDateTime.now().withHour(12).withMinute(0).withSecond(0).minusDays(7)
  exists( CheckedOutBook( checkedOutOn.isBefore($checkoutLimit) ) from $books )
then
  // TODO this is not ok
end


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Cool. We're almost done. Now we just need to get the results out to the caller. This is another commonly asked question topic in StackOverflow; I'll post about it some other time at length, but basically we have three options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create some sort of "result" object and pass it into working memory; in the 'then' clause, update this result object with the results from the rule.&lt;/li&gt;
&lt;li&gt;Create some sort of "result" object and set it as a global variable. This is nearly the same as 1, but more "old school" and you can't key off of the state of the result object in your "when" clause (not that we need to in our current application.)&lt;/li&gt;
&lt;li&gt;Invoke a method or other action which has a side effect that is visible to the caller.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For the sake of simplicity, we're going to go with option 2. Our results object will look like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookEventResult&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// getters and setters&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And now all we have to do is update our rules to set &lt;code&gt;success&lt;/code&gt; to false and a &lt;code&gt;reason&lt;/code&gt; in the right hand side of each rule. We'll also want to declare the &lt;code&gt;global&lt;/code&gt; at the top of the DRL. Here's one rule done as an example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

global BookEventResult result;

rule "Person has an overdue book"
when
  BookEvent( type == BookEventType.BORROW )
  Person( $books: checkedOutBooks )

  $checkoutLimit: OffsetDateTime() from OffsetDateTime.now().withHour(12).withMinute(0).withSecond(0).minusDays(7)
  exists( CheckedOutBook( checkedOutOn.isBefore($checkoutLimit) ) from $books )
then
  result.setSuccess(false);
  result.setReason("User has overdue book(s)");
end


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To tie it all together, we update the calling function and it's done. Huzzah!&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

&lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;processEvent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BookEvent&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// First, get the necessary data from the database&lt;/span&gt;
    &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getUserFromEvent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Create the result object&lt;/span&gt;
    &lt;span class="nc"&gt;BookEventResult&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BookEventResult&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Call the rules&lt;/span&gt;
    &lt;span class="nc"&gt;KieServices&lt;/span&gt; &lt;span class="n"&gt;kieServices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;KieServices&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;KieContainer&lt;/span&gt; &lt;span class="n"&gt;kContainer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kieServices&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getKieClasspathContainer&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;KieBase&lt;/span&gt; &lt;span class="n"&gt;kBase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kContainer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getKieBase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kbaseName&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nc"&gt;KieSession&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kBase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newKieSession&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;insert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; 
    &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;insert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; 
    &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setGlobal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"result"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fireAllRules&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// handle the result&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isSuccess&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to checkout book. Reason = "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getReason&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getType&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;BookEventType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BORROW&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
        &lt;span class="n"&gt;borrowBook&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;returnBook&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The implementation of the &lt;code&gt;borrowBook&lt;/code&gt; and &lt;code&gt;returnBook&lt;/code&gt; functions left as an exercise for the reader. In these methods, we should actually implement the business logic involved in borrowing or returning a book, which will involve updating the appropriate rows in the database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Um, but wait ...
&lt;/h3&gt;

&lt;p&gt;Yes, this is a toy example. Yes we've got some pretty sizable gaps in our error handling. Consider these following use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What if the book that we're trying to check out is already checked out by someone else?&lt;/li&gt;
&lt;li&gt;What if a concurrent request comes in for the same user which puts them over the checked out limit?&lt;/li&gt;
&lt;li&gt;What if the validity of the action changes between the rules determining go/no-go and the actual invocation of the &lt;code&gt;borrowBook&lt;/code&gt;/&lt;code&gt;returnBook&lt;/code&gt; methods?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are all valid questions. But here's the thing -- we can handle them. And when we handle them &lt;em&gt;they will be handled in code&lt;/em&gt;. Not rules. Because the whole point of this exercise was to implement our validations in the rules without having to touch the database from the DRL itself.&lt;/p&gt;

&lt;p&gt;And in that regard we've been successful. Before invoking the rules, we get our data from the database. We are then able to invoke the database with a snapshot of the data at the current point in time. When we finish, we have our result, and can now update the database.&lt;/p&gt;

&lt;p&gt;At minimum, what we should be doing is checking that the state that we ran against the rules is the same state that the database is in when we try to apply the user action. If something has changed in the meantime, we can terminate the request with an HTTP 409 Conflict (or equivalent if not in an HTTP API or not using HTTP status codes.) This sort of response will indicate that yes, we tried to do the thing you asked, but there was a conflict that occurred -- likely a conflicting request that changed state before we were able to apply our changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The end of the road
&lt;/h2&gt;

&lt;p&gt;And that is that. Hopefully you now understand why interacting with a database from inside of a DRL directly is bad, interacting with a DAO from inside of a DRL is only marginally better, and what you should actually be doing is doing all of your database GETs/READs first and then calling the rules and then doing any necessary SAVEs for your updated state.&lt;/p&gt;

&lt;p&gt;(Now if you &lt;em&gt;really&lt;/em&gt; want to kick over an anthill, find a bunch of DBAs and ask them their opinion on saving derived or calculated data in a database. If they had their way, we'd never be saving anything that we "calculated" in rules into the DB.)&lt;/p&gt;

&lt;p&gt;Thanks for sticking with me on this extended rant about Drools and databases. Hopefully it made sense; if not feel free to leave a message. All sample applications were made up on the fly and do not represent any real production application that I know of or have worked on.&lt;/p&gt;

&lt;p&gt;And, as always, happy coding!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cover image attribution: &lt;a href="https://pixabay.com/photos/train-station-railroad-to-travel-3487588/" rel="noopener noreferrer"&gt;ulleo @ Pixabay&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>drools</category>
    </item>
    <item>
      <title>Drools &amp; Databases, Part 2: Don't Call the DAO from the DRL</title>
      <dc:creator>Roddy</dc:creator>
      <pubDate>Wed, 25 Aug 2021 06:41:34 +0000</pubDate>
      <link>https://dev.to/roddy/drools-databases-part-2-don-t-call-the-dao-from-the-drl-8c6</link>
      <guid>https://dev.to/roddy/drools-databases-part-2-don-t-call-the-dao-from-the-drl-8c6</guid>
      <description>&lt;p&gt;One of the most common questions on StackOverflow in the &lt;a href="https://stackoverflow.com/questions/tagged/drools"&gt;Drools tag&lt;/a&gt; is something along the lines of "how do I call my database from my &lt;a href="https://drools.org/"&gt;rules&lt;/a&gt;?"&lt;/p&gt;

&lt;p&gt;The short answer is "you shouldn't." The longer answer is "it's complicated." This is the second in a series of posts explaining why.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://dev.to/roddy/drools-databases-part-1-don-t-call-the-db-from-the-drl-3hg3"&gt;Last time&lt;/a&gt;, we discussed why you shouldn't be writing database access functions directly in your DRL files. Today we're going to talk about why even a properly designed and hardened database access layer shouldn't be invoked from Drools.&lt;/p&gt;

&lt;p&gt;Before we begin, let me define what I mean by "properly designed and hardened database access layer." We're going to assume an application has been implemented that has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;transaction management for all database access methods (for example, consider Hibernate's &lt;code&gt;@Transactional&lt;/code&gt; annotation and similar mechanisms)&lt;/li&gt;
&lt;li&gt;query sanitization of all inputs into queries&lt;/li&gt;
&lt;li&gt;connection pooling for all connections (eg. C3P0 or Apache Commons DBCP)&lt;/li&gt;
&lt;li&gt;appropriate security, access restrictions, credential management, and role management around database access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Further, we will assume that the application exposes a service class or interface through which we can interact with the database. This might be something like a &lt;a href="https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#reference"&gt;Spring Data JPA&lt;/a&gt; repository, or some other form of DAO. For the purpose of this article, we'll assume that this class or interface exposes methods which return simple Java objects or collections of objects that model the results of the query. We make no assumptions about the design of those returned objects -- maybe they're annotated DTOs or entities; maybe they're just POJOs or JDK 14 Records.&lt;/p&gt;

&lt;p&gt;Now that we've got that squared away, we'll get down to the meat of the problem ... namely:&lt;/p&gt;

&lt;h2&gt;
  
  
  Drools doesn't execute stuff like you think it does
&lt;/h2&gt;

&lt;p&gt;Let's begin with a caveat. &lt;em&gt;Technically&lt;/em&gt; if you take the time and effort to properly design your data access layer and address the concerns listed in the introduction and in the previous article, then you &lt;em&gt;technically&lt;/em&gt; can go about calling your database from within your rules.&lt;/p&gt;

&lt;p&gt;But you shouldn't, and this time, the reason has less to do with your database and more to do with Drools itself.&lt;/p&gt;

&lt;p&gt;Namely this: most people don't properly understand the Drools lifecycle.&lt;/p&gt;

&lt;p&gt;Why does this matter? Because unless you maintain extremely strict standards in your rule design forever, and familiarize yourself with how the Drools engine works in terms of execution and rule matching, you're going to be executing your queries a lot more often than you think. This leads to a bunch of potential issues:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Latency.&lt;/strong&gt; Database calls aren't "free". Every time a thread executes the rules and makes queries, they'll be using a connection and preparing a statement and executing it and parsing the results. If you have one thread, that's probably not so noticeable. But once you scale up, even with the best connection pooling, you're going to be seeing lag. You'll be seeing &lt;em&gt;even more&lt;/em&gt; lag if you implement your rules naively (that is, without understanding how the Drools engine works.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data consistency.&lt;/strong&gt; A database is a shared resource. When you make query, you get a snapshot of the data at a specific point in time. Every time you repeat the query, you're adding the potential that the records have changed out from under you -- what was necessarily true at the time you made the previous query may no longer be true anymore.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are other issues as well, but these are the top two.&lt;/p&gt;

&lt;p&gt;Let's look at an example which illustrates the issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  A simple example
&lt;/h3&gt;

&lt;p&gt;Our example application provides order tracking and invoice generation via some rules. I'm going to use &lt;a href="https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/lang/Record.html"&gt;JDK14 Records&lt;/a&gt; to model the data, but you can easily imagine them as POJOs instead.&lt;/p&gt;

&lt;p&gt;For the purpose of our rules, our application has three models:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Customer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="no"&gt;UUID&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Invoice&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;invoices&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="no"&gt;UUID&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;UUID&lt;/span&gt; &lt;span class="n"&gt;customerId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Float&lt;/span&gt; &lt;span class="n"&gt;appliedTax&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Invoice&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've also abstracted all of our database logic into a service, &lt;code&gt;CustomerOrdersService&lt;/code&gt;. Our particular example will only make use of two methods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="nf"&gt;getLatestOrderForCustomer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;UUID&lt;/span&gt; &lt;span class="n"&gt;customerId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;updateOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that &lt;code&gt;updateOrder&lt;/code&gt; will perform a database save. We'll assume that any auditing (eg. user/date updated) are out of scope and happen somewhere offscreen.&lt;/p&gt;

&lt;p&gt;And finally, we have a utility class &lt;code&gt;TaxUtils&lt;/code&gt; for some tax-related logic. We also have a &lt;a href="https://cleancoders.com/episode/clean-code-episode-26"&gt;factory&lt;/a&gt; &lt;code&gt;InvoiceFactory&lt;/code&gt; for generating invoices.&lt;/p&gt;

&lt;p&gt;So, for our application we've got the following use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the latest order for the customer is missing tax information, calculate the applied tax and update the order.&lt;/li&gt;
&lt;li&gt;If the latest order for the customer has all required information (in this example, tax info), generate an invoice for the order and apply it to the customer account.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a first pass, our rules might look something like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;rule&lt;/span&gt; &lt;span class="s"&gt;"Customer Order is Missing Tax Information"&lt;/span&gt;
&lt;span class="n"&gt;when&lt;/span&gt;
  &lt;span class="n"&gt;$svc&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;CustomerOrdersService&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;

  &lt;span class="nc"&gt;Customer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="n"&gt;$id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;$order&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="n"&gt;appliedTax&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;$svc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLatestOrderForCustomer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;$id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;then&lt;/span&gt;
  &lt;span class="c1"&gt;// calculate and apply the tax using some external utility&lt;/span&gt;
  &lt;span class="nc"&gt;TaxUtils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;applyTax&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;$order&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// update the database record&lt;/span&gt;
  &lt;span class="n"&gt;$svc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;updateOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;$order&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;rule&lt;/span&gt; &lt;span class="s"&gt;"Generate Invoice for Customer Order"&lt;/span&gt;
&lt;span class="n"&gt;when&lt;/span&gt;
  &lt;span class="n"&gt;$svc&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;CustomerOrdersService&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;

  &lt;span class="n"&gt;$customer&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Customer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="n"&gt;$id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;$order&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="n"&gt;appliedTax&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;$svc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLatestOrderForCustomer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;$id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;then&lt;/span&gt;
  &lt;span class="nc"&gt;Invoice&lt;/span&gt; &lt;span class="n"&gt;invoice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;InvoiceFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;generate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;$order&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;$customer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addInvoice&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are two big problems here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem 1: we call &lt;code&gt;getLatestOrderForCustomer&lt;/code&gt; twice.&lt;/strong&gt; We incur the latency of &lt;em&gt;two&lt;/em&gt; database calls where one would have sufficed. Further, it is possible that a new Order may have been added to the database while Drools was evaluating these rules. That means that the first rule may be working on Order 5, and the second rule may be working with Order 6.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem 2: the order update is invisible.&lt;/strong&gt; The first rule handles a use case where we're missing some necessary data (tax). On the left hand side we check that we're missing it, and on the right hand side we calculate it and save the results to the database. Now our data is good in the database, but what about the rule to generate invoices? It will never fire because we checked previously that there &lt;em&gt;was&lt;/em&gt; tax information present when we were deciding whether or not to fire the rules -- and at that time there was no tax information. In order to actually get the second rule to fire in this case, we'd need to do an &lt;code&gt;update&lt;/code&gt; call to re-trigger the evaluation of all rules, which means we'll be calling the database two &lt;em&gt;more&lt;/em&gt; times and thus exacerbating problem 1.&lt;/p&gt;

&lt;p&gt;If you look at a Drools rule file, it's easy to fall into the trap of thinking that Drools will evaluate each rule sequentially: read the when, and execute the then; then read the next when, and execute its then. That's not actually how Drools works, however, and that's the trap that these example rules have fallen into.&lt;/p&gt;

&lt;p&gt;The Drools lifecycle has various "phases", but we're specifically going to just talk about the 'Matching' phase. When you call "fire rules", Drools first gathers up all of the available rules, sorts them by salience and natural order, and then iterates across them evaluating the "when" clause. For a given rule, if all the statements in the "when" clause evaluate successfully then the rules engine considers this a "match" and it adds it to an ordered list of "matched" rules. (Hint: if you implement a rule listener, you can watch for the 'Match Created' event.)&lt;/p&gt;

&lt;p&gt;Once all of the rules' left hand sides have been evaluated, the rules engine takes that list of matches and iterates over them, evaluating the right hand side.&lt;/p&gt;

&lt;p&gt;This is why database access on the left hand side of the rule is so problematic -- the database queries are run during the 'match' phase, which means that any changes to the database values will be "invisible" unless the rule engine re-evaluates its previous matches. Drools does make such reevaluation possible through the use of some built-in functions -- &lt;code&gt;update&lt;/code&gt;, &lt;code&gt;insert&lt;/code&gt;, &lt;code&gt;modify&lt;/code&gt;, etc. Once you do call these methods, Drools will reevaluate the matches, redoing those database calls and incurring the inherent latency and danger of data inconsistency therein.&lt;/p&gt;

&lt;h3&gt;
  
  
  A simple refactor
&lt;/h3&gt;

&lt;p&gt;Let's attempt to refactor our rules to address the problems we previously identified. &lt;/p&gt;

&lt;p&gt;For data consistency and latency concerns, we'll want to call our &lt;code&gt;getLatestOrderForCustomer&lt;/code&gt; exactly one time. Further, we'll need to make sure our changes to the &lt;code&gt;order&lt;/code&gt; instance (the calculated tax applied) to be visible to all rules without requiring a new call to the database.&lt;/p&gt;

&lt;p&gt;Here's what we get by applying these requirements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;rule&lt;/span&gt; &lt;span class="s"&gt;"Get Latest Order"&lt;/span&gt;
&lt;span class="n"&gt;when&lt;/span&gt;
  &lt;span class="n"&gt;$svc&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;CustomerOrdersService&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;not&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="nc"&gt;Customer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="n"&gt;$id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;then&lt;/span&gt;
  &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;$order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;$svc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLatestOrderForCustomer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;$id&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;$order&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;rule&lt;/span&gt; &lt;span class="s"&gt;"Customer Order is Missing Tax Information - v2"&lt;/span&gt;
&lt;span class="n"&gt;when&lt;/span&gt;
  &lt;span class="n"&gt;$svc&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;CustomerOrdersService&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;

  &lt;span class="c1"&gt;// Check the order in working memory&lt;/span&gt;
  &lt;span class="n"&gt;$order&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="n"&gt;appliedTax&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;then&lt;/span&gt;
  &lt;span class="c1"&gt;// calculate and apply the tax using some external utility&lt;/span&gt;
  &lt;span class="nc"&gt;TaxUtils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;applyTax&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;$order&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// update the database record&lt;/span&gt;
  &lt;span class="n"&gt;$svc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;updateOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;$order&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;$order&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;rule&lt;/span&gt; &lt;span class="s"&gt;"Generate Invoice for Customer Order - v2"&lt;/span&gt;
&lt;span class="n"&gt;when&lt;/span&gt;
  &lt;span class="n"&gt;$customer&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Customer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="n"&gt;$id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;$order&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="n"&gt;appliedTax&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;then&lt;/span&gt;
  &lt;span class="nc"&gt;Invoice&lt;/span&gt; &lt;span class="n"&gt;invoice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;InvoiceFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;generate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;$order&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;$customer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addInvoice&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a little more complex, but we should have addressed the biggest concerns.&lt;/p&gt;

&lt;p&gt;First, we've added a new rule -- &lt;code&gt;"Get Latest Order"&lt;/code&gt;. This rule checks to see if there's an order in working memory; if there's not, it does a lookup and adds it. It calls &lt;code&gt;insert&lt;/code&gt;, which will tell Drools to re-evaluate subsequent rules to see if they're now matches.&lt;/p&gt;

&lt;p&gt;You'll also notice that the other two rules have been updated to use the Order information in working memory instead of doing the database lookup themselves. This restructuring means that we should be calling the &lt;code&gt;getLatestOrderForCustomer&lt;/code&gt; method only once per execution, which should take care of most of our problems regarding latency and data integrity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem 1.&lt;/strong&gt; We only call &lt;code&gt;getLatestOrderForCustomer&lt;/code&gt; once, and that's on the right hand side (RHS) of the rules, so it's not going to be called extraneously during the matching phase. Only when this specific rule matches will the rule be called; the consequences in this rule also adjust working memory so that the rule will no longer be eligible to fire a second time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem 2.&lt;/strong&gt; Since we're doing work on an Order instance in working memory, we no longer need to be concerned about the tax changes being invisible to the invoice rule. Because the Order is in working memory, we can call &lt;code&gt;update&lt;/code&gt; on it after we make the changes and that will reevaluate the rules and trigger the invoice rule because of the newly non-null value.&lt;/p&gt;

&lt;p&gt;So what problems do we have left?&lt;/p&gt;

&lt;h3&gt;
  
  
  Maintenance: the hidden debt
&lt;/h3&gt;

&lt;p&gt;Technically, without adding any more color to the use cases and methods I've presented, there's nothing wrong with the rules as written. Without any more complexities or "gotachas", the rules as written would suffice, and we could use them as-is in our application. But should we?&lt;/p&gt;

&lt;p&gt;I would argue that no, you shouldn't. Not because the rules are &lt;em&gt;bad&lt;/em&gt; -- because they're really not -- but because they're fragile.&lt;/p&gt;

&lt;p&gt;From now on, any engineer who you ask to maintain these rules will need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;understand the intricacies of the Drools lifecycle&lt;/strong&gt;, namely how the "matching" phase works and how different actions (eg. &lt;code&gt;update&lt;/code&gt;, &lt;code&gt;modify&lt;/code&gt;, &lt;code&gt;insert&lt;/code&gt;, etc) cause the phase to be re-evaluated&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;be intimately familiar with your data access layer and models&lt;/strong&gt;, especially regarding how data is fetched and modelled&lt;/li&gt;
&lt;li&gt;understand how the two interact with each other&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is further complicated by the fact that it's not really feasible to create test scenarios -- automated or otherwise -- against the problems we're guarding against. Recall that one of the problems I initially called out was that we get the "latest" order twice; thus if a new order was inserted into the database during the matching phase, it would be possible that two different orders were being evaluated simultaneously in different rules. This would be spectacularly difficult to test -- honestly, I can't think of how to induce the scenario consistently (at least, not without significantly modifying the Drools runtime and the production code.)&lt;/p&gt;

&lt;p&gt;It's not unreasonable to ask a software engineer to consider race conditions, of course. If we had a method where we called "get latest" twice, it would be reasonable to expect an experience engineer to recognize that potentially the second call may return a different value than the first. A junior engineer may not notice this weakness, however, and may implement the sequential calls, even in a simple code context. (After all, you want to make sure your data isn't stale, right? What better than to get a fresh copy every time?) Personally, I wouldn't fault an entry-level engineer for overlooking this; with experience comes seniority -- but do you really want to restrict your rules to only being updated by senior engineers? And, given the inability to test for the problems that arise from &lt;em&gt;not&lt;/em&gt; understanding these complexities -- do you really want to have to rely on equally senior but still very human code reviewers to notice, identify, and flag potential workflow issues?&lt;/p&gt;

&lt;p&gt;That's the crux of the problem really. You're relying on two very particular and complex technologies -- Drools rule execution and database access -- both of which have their own distinct problems, but which together present an additional set of combined challenges that one can only readily identify and work with if an engineer understands both knowledge domains. And the worst part? You can't reliably produce automated tests for these issues, so new problems are likely to be identified only in production.&lt;/p&gt;

&lt;p&gt;At the end of the day, my argument really boils down to some software engineering principles. KISS -- Keep It Simple, Stupid -- and the Single Responsibility Principle. The purpose of a database is to provide data access; the purpose of Drools or any rules system is to make decisions against inbound data; access your data &lt;em&gt;first&lt;/em&gt;, and then you can make decisions at your leisure. And, honestly, most software engineering could benefit from KISS: not only does it make your life simpler today, but it reduces your maintenance overhead tomorrow. If your rules don't interact with your database, you don't need to worry about a well meaning intern showing up several years down the road and making an innocent change in response to a bug that causes millions of dollars' worth of consequences. (True story.)&lt;/p&gt;

&lt;h2&gt;
  
  
  The End
&lt;/h2&gt;

&lt;p&gt;Honestly, my examples weren't even as complex as they could be. Consider, for example, what might happen if the model returned by our data access layer included a Hibernate lazily loaded collection. Such a collection can only be loaded if we have an active transaction (eg. we need to be inside the &lt;code&gt;@Transactional&lt;/code&gt; context); we're safe as long as the rules never interact with that collection ... but what if they &lt;em&gt;potentially&lt;/em&gt; need to? Should we eagerly load the collection, just in case, and take the performance hit? Or do we need to somehow get a transaction to do the lazy-load only when we need it?&lt;/p&gt;

&lt;p&gt;At this point I'm belaboring the point, and I hope that I've made it clear why you shouldn't access databases from Drools even with a hardened, production-ready data access layer. &lt;/p&gt;

&lt;p&gt;Like part 1, this isn't actually the end of my extended rant against database access in Drools -- it's just the wrap-up of part 2 this monologue. Stay tuned for part 3!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cover image attribution: &lt;a href="https://pixabay.com/photos/prairie-river-stream-curved-sunset-679014/"&gt;cowins @ Pixabay&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>drools</category>
    </item>
    <item>
      <title>Drools &amp; Databases, Part 1: Don't Call the DB from the DRL</title>
      <dc:creator>Roddy</dc:creator>
      <pubDate>Fri, 14 May 2021 05:53:42 +0000</pubDate>
      <link>https://dev.to/roddy/drools-databases-part-1-don-t-call-the-db-from-the-drl-3hg3</link>
      <guid>https://dev.to/roddy/drools-databases-part-1-don-t-call-the-db-from-the-drl-3hg3</guid>
      <description>&lt;p&gt;One of the most commonly asked &lt;a href="https://drools.org/"&gt;Drools&lt;/a&gt; questions that I see on &lt;a href="https://stackoverflow.com/questions/tagged/drools"&gt;StackOverflow&lt;/a&gt; is something along the lines of "How do I do a database query from Drools?"&lt;/p&gt;

&lt;p&gt;The answer is simply: you don't.&lt;/p&gt;

&lt;p&gt;OK, to be entirely truthful, you can but you shouldn't. This is the first in a series of posts in which I'm going to explain why.&lt;/p&gt;

&lt;p&gt;Today we're going to talk about the problems on the database side of things; namely:&lt;/p&gt;

&lt;h2&gt;
  
  
  Database Access is Hard (to do right)
&lt;/h2&gt;

&lt;p&gt;It's actually pretty easy to interact with a database in Java. Even if you're using the built-in &lt;a href="https://docs.oracle.com/en/java/javase/13/docs/api/java.sql/java/sql/package-summary.html"&gt;JDBC APIs&lt;/a&gt; (eg. &lt;code&gt;java.sql.Statement&lt;/code&gt;, etc.), it's just not that hard to open a connection, execute a statement, and get results. Libraries like Spring Data and JPA abstract even more away, sometimes going as far as automatically generating your queries for you.&lt;/p&gt;

&lt;p&gt;But like many things, just because it's easy to do doesn't necessarily mean you're doing it right. For a toy application, you can get away with a lot of stuff. But as soon as you scale to production, now you need to think about things like connection pooling, transaction management &amp;amp; rollbacks, distributed transactions, backups, audits, and all the other fun stuff that comes with exposing an application to Actual Users.&lt;/p&gt;

&lt;p&gt;What this means is that doing a naive JDBC query like this in your Drools ...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// in a DRL file ...&lt;/span&gt;
&lt;span class="c1"&gt;// DO NOT DO THIS. PLEASE.&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.sql.Connection&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.sql.DriverManager&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.sql.Statement&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.sql.ResultSet&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getCustomerNameFromDatabase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;UUID&lt;/span&gt; &lt;span class="n"&gt;customerId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.mysql.jdbc.Driver"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="nc"&gt;Connection&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DriverManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getConnection&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
      &lt;span class="s"&gt;"jdbc:mysql://my-db.example.com:33000/something"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="s"&gt;"admin"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="s"&gt;"Secr3t P@ssWd!"&lt;/span&gt;
  &lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="nc"&gt;Statement&lt;/span&gt; &lt;span class="n"&gt;statement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createStatement&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="nc"&gt;ResultSet&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;statement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;executeQuery&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"select * from Customer where customer_id='"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;customerId&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"'"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;first&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"customer_name"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;rule&lt;/span&gt; &lt;span class="s"&gt;"Example Rule"&lt;/span&gt;
&lt;span class="n"&gt;when&lt;/span&gt;
  &lt;span class="n"&gt;$invoice&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Invoice&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="n"&gt;$customerId&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;custId&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;$customerName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="nf"&gt;getCustomerNameFromDatabase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;$customerId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="nc"&gt;Receipt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="n"&gt;purchaser&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;$customerName&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;then&lt;/span&gt;
  &lt;span class="c1"&gt;// simple use case: the customer name for the customer on the invoice&lt;/span&gt;
  &lt;span class="c1"&gt;// does not match the customer name on the receipt.&lt;/span&gt;
&lt;span class="n"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... is an &lt;em&gt;absolute&lt;/em&gt; no-no. &lt;/p&gt;

&lt;p&gt;Will it work? Yes, technically. In a toy app or a proof-of-concept that will be run once and never again, then &lt;em&gt;maybe&lt;/em&gt; it is "ok". But is it OK for production? &lt;em&gt;Absolutely not.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Ignoring the fact that we're not doing any connection pooling or transaction management -- where's your error handling? What happens if your SQL statement is malformed? What happens if your connection is closed from under you? Heck, what happens if one of these statements throws an exception?&lt;/p&gt;

&lt;p&gt;Where do you make sure your connection actually gets closed?&lt;/p&gt;

&lt;p&gt;And don't &lt;em&gt;even&lt;/em&gt; get me started about the hard-coded database credentials saved in plaintext in your DRL file. Or the fact that we're not sanitizing our inputs.&lt;/p&gt;

&lt;h3&gt;
  
  
  A slightly more realistic example
&lt;/h3&gt;

&lt;p&gt;... But ok, yes, I admit that's a contrived example. Hopefully by now you know that you need to handle things like Exceptions and do things like close your connections, statements, etc. after you use them, even if an exception occurs.&lt;/p&gt;

&lt;p&gt;If we were doing this in Java, I would absolutely suggest using &lt;a href="https://www.baeldung.com/java-try-with-resources"&gt;try-with-resources&lt;/a&gt; for these elements, since the major classes do properly implement &lt;a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/AutoCloseable.html"&gt;AutoCloseable&lt;/a&gt;. However DRL files don't support the full Java SDK, primarily because they're interpreted files rather than compiled -- the Drools framework parses these files as strings and then compiles the bits as needed, with a little DSL magic. (That's a topic for another post, though!)&lt;/p&gt;

&lt;p&gt;The point is that while try-with-resources is the modern Java 8+ way of doing our connection management to make sure we properly close our connections, statements, and other sockets, we can't use that in our DRL declared function. As a result, we're going to have to go use something that looks more "old school" ... and I'm meaning Java 5-style "old school".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getCustomerNameFromDatabase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;UUID&lt;/span&gt; &lt;span class="n"&gt;customerId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.mysql.jdbc.Driver"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="nc"&gt;Connection&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="nc"&gt;Statement&lt;/span&gt; &lt;span class="n"&gt;statement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="nc"&gt;ResultSet&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DriverManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getConnection&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"jdbc:mysql://my-db.example.com:33000/something"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"admin"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"Secr3t P@ssWd!"&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;statement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createStatement&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;statement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;executeQuery&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"select * from Customer where customer_id='"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;customerId&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"'"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;first&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"customer_name"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;nill&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;ignored&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;statement&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;statement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;ignored&lt;/span&gt;&lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;ignored&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there we go, that's our dangling &lt;code&gt;Connection&lt;/code&gt;, &lt;code&gt;Statement&lt;/code&gt;, and &lt;code&gt;ResultSet&lt;/code&gt; taken care of. Nasty, eh?&lt;/p&gt;

&lt;p&gt;But wait! There's more! After all, we're still vulnerable to SQL injection -- look at those unsanitized SQL queries!&lt;/p&gt;

&lt;h3&gt;
  
  
  Some basic cleanup
&lt;/h3&gt;

&lt;p&gt;The simplest way to go about this would be to replace our naive string-concatenation with a &lt;a href="https://docs.oracle.com/javase/7/docs/api/java/sql/PreparedStatement.html"&gt;PreparedStatement&lt;/a&gt;. This isn't actually that big of a deal to change, all things considered.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getCustomerNameFromDatabase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;UUID&lt;/span&gt; &lt;span class="n"&gt;customerId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;  
  &lt;span class="nc"&gt;Connection&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="nc"&gt;PreparedStatement&lt;/span&gt; &lt;span class="n"&gt;statement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="nc"&gt;ResultSet&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.mysql.jdbc.Driver"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DriverManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getConnection&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"jdbc:mysql://my-db.example.com:33000/something"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"admin"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"Secr3t P@ssWd!"&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"select * from Customer where customer_id=?"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;statement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prepareStatement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;statement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;customerId&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;statement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;executeQuery&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;first&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"customer_name"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;nill&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;ignored&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;statement&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;statement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;ignored&lt;/span&gt;&lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;ignored&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Honestly this is getting tedious, so fixing the ResultSet is left as an exercise for the reader. Consider: what do we do if the query returns no rows? more than one row?&lt;/p&gt;

&lt;p&gt;The last part we'll address is the exposed database credentials. Here we're unfortunately trying to work around a limitation of the subset of languge features available in DRL functions: we can't use the DriverManager in its entirety because it relies on properties being automatically loaded from the classpath. This isn't available natively in DRL functions, so we're using the old-school &lt;code&gt;Class.forName&lt;/code&gt; method which went out of vogue with Java 7. &lt;/p&gt;

&lt;p&gt;A better design would be, admittedly, to pass the credentials into working memory. That would, at least, keep them from being hard-coded in plain-text in the DRL file itself.&lt;/p&gt;

&lt;p&gt;So we'll create a simple POJO to pass into the rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DbConnectionInfo&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// getters, setters omitted for brevity&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... and then pass that from the rules to the function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getCustomerNameFromDatabase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DbConnectionInfo&lt;/span&gt; &lt;span class="n"&gt;connectionInfo&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;UUID&lt;/span&gt; &lt;span class="n"&gt;customerId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;  
  &lt;span class="nc"&gt;Connection&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="nc"&gt;PreparedStatement&lt;/span&gt; &lt;span class="n"&gt;statement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="nc"&gt;ResultSet&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.mysql.jdbc.Driver"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DriverManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getConnection&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;connectionInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUrl&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;connectionInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUsername&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;connectionInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPassword&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"select * from Customer where customer_id=?"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;statement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prepareStatement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;statement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;customerId&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;statement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;executeQuery&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;first&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"customer_name"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;nill&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;ignored&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;statement&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;statement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;ignored&lt;/span&gt;&lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;ignored&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;rule&lt;/span&gt; &lt;span class="s"&gt;"Example Rule"&lt;/span&gt;
&lt;span class="n"&gt;when&lt;/span&gt;
  &lt;span class="n"&gt;$cxnInfo&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;DbConnectionInfo&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;

  &lt;span class="n"&gt;$invoice&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Invoice&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="n"&gt;$customerId&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;custId&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;$customerName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="nf"&gt;getCustomerNameFromDatabase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;$cxnInfo&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;$customerId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="nc"&gt;Receipt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="n"&gt;purchaser&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;$customerName&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;then&lt;/span&gt;
  &lt;span class="c1"&gt;// simple use case: the customer name for the customer on the invoice&lt;/span&gt;
  &lt;span class="c1"&gt;// does not match the customer name on the receipt.&lt;/span&gt;
&lt;span class="n"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there we go. Still awful, but marginally less so. &lt;/p&gt;

&lt;h3&gt;
  
  
  But that doesn't mean it's any good
&lt;/h3&gt;

&lt;p&gt;Even with all that work, and 31 lines of code (not counting the not-yet-implemented ResultSet cleanup), this is just &lt;em&gt;one&lt;/em&gt; database query, and it's spectacularly not production-ready.&lt;/p&gt;

&lt;p&gt;For any production-grade database access, there's a certain minimum of hardening we need to do to properly prepare for the transactional volumes inherent in real-world applications.&lt;/p&gt;

&lt;p&gt;Looking back at our example, you'll notice that we've got a pretty basic implementation, courtesy of the JDBC API. This is fine for when you're learning, but nobody that I know of actually uses pure JDBC like this in production. Our implementation doesn't support connection pooling or transaction management. And, honestly, the only way I know how to implement either of those is with libraries that aren't compatible with DRL functions.&lt;/p&gt;

&lt;p&gt;I mentioned this previously, but the Java language features available for use in the DRL are a very restricted subset of the full Java language. Database interactions with modern libraries rely on features that are simply not available in DRL functions. We can't just slap a &lt;code&gt;@Transactional&lt;/code&gt; annotation on the DRL function (no annotations in DRL! Or, well, not like this.) I suppose it &lt;em&gt;might&lt;/em&gt; be possible to implement connection pooling via something like c3p0, but it would be likely a hundred or more lines of code and the results would be sub-optimal.&lt;/p&gt;

&lt;p&gt;Moving beyond database hardening, the other major issue here is that this approach simply does not scale. In our example, all we're trying to do is get the Customer's name from the database. That's one very simple query, for one very distinct use case. No application ever stays that small for long. As the application grows and additional rules are implemented, each subsequent query will need to go through this same process and face these same issues. &lt;/p&gt;

&lt;p&gt;Just one database "getter" function and its dependent rule was already a 31-to-5 line ratio. Can you just imagine how huge your DRL files will be as your application and number of queries scale? &lt;/p&gt;

&lt;p&gt;Not only that, but imagine more complex queries. Our example was a trivial &lt;code&gt;SELECT *&lt;/code&gt; to retrieve one row per certain conditions. Now imagine what update calls would look like, and how you'd have to implement (manually) roll backs. Or consider a delete call that cascades across multiple tables.&lt;/p&gt;

&lt;p&gt;At the end of the day, DRL functions have a place and a purpose -- and this is not it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The End
&lt;/h2&gt;

&lt;p&gt;This isn't actually the end, we're just wrapping up this first section of my extended rant about why you shouldn't be trying to access the database from your rules. In this post we covered why you shouldn't try to do this by implementing DRL functions directly. &lt;a href="https://dev.to/roddy/drools-databases-part-2-don-t-call-the-dao-from-the-drl-8c6"&gt;Next time&lt;/a&gt; I'll talk about why even a properly implemented data access layer shouldn't be invoked from the rules.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cover image attribution: &lt;a href="https://pixabay.com/photos/mountains-stream-grass-brook-6231396/"&gt;trondmyhre4 @ Pixabay&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>drools</category>
    </item>
  </channel>
</rss>
