tag:blogger.com,1999:blog-80760328517366578382024-03-13T11:17:55.934-04:00OOP UniversityA place to learn object oriented programming from a Java-centric perspective. We sometimes explore other models as well, when my job demands that I learn something I try to pass it on.J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.comBlogger47125tag:blogger.com,1999:blog-8076032851736657838.post-38444621447625545992024-03-05T09:35:00.004-05:002024-03-05T09:36:11.676-05:00An Open and Shut Case for the Open-Closed Principle<p> <span style="background-color: white; color: #0d0d0d; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; white-space-collapse: preserve;">The "O" from the SOLID principles of software architecture stands for the Open-Closed Principle (OCP). This principle states that software entities (classes, modules, functions, etc.) should be open for extension but closed for modification. In other words, we should be able to add new features or behaviors to a software entity without changing its existing code.</span></p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: #0d0d0d; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;"><span style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-bold); font-weight: 600;">Why is this principle important?</span> Because it helps us achieve two main goals: maintainability and reusability. By following the OCP, we can avoid breaking existing functionality when we add new features, and we can also reuse existing code without having to modify it for different scenarios.</p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: #0d0d0d; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;"><span style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-bold); font-weight: 600;">How can we apply the OCP in practice?</span> One common way is to use abstraction and polymorphism. Abstraction means hiding the details of how something works and exposing only what it does. Polymorphism means having different implementations of the same abstraction that can be used interchangeably. For example, we can define an abstract class or interface that represents a shape, and then have different subclasses or implementations that represent specific shapes, such as circles, squares, triangles, etc. We can then write code that works with any shape without knowing its specific type or details.</p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: #0d0d0d; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;">Another way to apply the OCP is to use dependency inversion. This means depending on abstractions rather than concrete implementations. For example, instead of having a class that directly uses a database or a file system to store data, we can have a class that depends on an abstract data source that can be implemented by different concrete data sources. This way, we can change the data source without changing the class that uses it.</p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: #0d0d0d; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;">To illustrate the OCP in action, let's consider a simple example of a calculator application. Suppose we have a class called <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-code); font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">Calculator</code> that performs basic arithmetic operations, such as addition, subtraction, multiplication, and division. The class has a method called <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-code); font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">calculate</code> that takes two numbers and an operator as parameters and returns the result of the operation. The method looks something like this:</p><pre style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border-radius: 0.375rem; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: #0d0d0d; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; line-height: 1.71429; margin-bottom: 0px; margin-top: 0px; overflow-x: auto; padding: 0px;"><div class="dark bg-gray-950 rounded-md" style="--border-heavy: hsla(0,0%,100%,.2); --border-light: hsla(0,0%,100%,.1); --border-medium: hsla(0,0%,100%,.15); --border-xheavy: hsla(0,0%,100%,.25); --link-hover: #5e83b3; --link: #7ab7ff; --main-surface-primary: var(--gray-800); --main-surface-secondary: var(--gray-700); --main-surface-tertiary: var(--gray-600); --sidebar-surface-primary: var(--gray-900); --sidebar-surface-secondary: var(--gray-800); --sidebar-surface-tertiary: var(--gray-700); --text-primary: var(--gray-100); --text-quaternary: var(--gray-500); --text-secondary: var(--gray-300); --text-tertiary: var(--gray-400); --tw-bg-opacity: 1; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border-radius: 0.375rem; border: 0px solid rgb(227, 227, 227); box-sizing: border-box;"><div class="flex items-center relative text-token-text-secondary bg-token-main-surface-secondary px-4 py-2 text-xs font-sans justify-between rounded-t-md" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; align-items: center; background-color: var(--main-surface-secondary); border-top-left-radius: 0.375rem; border-top-right-radius: 0.375rem; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--text-secondary); display: flex; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 0.75rem; justify-content: space-between; line-height: 1rem; padding: 0.5rem 1rem; position: relative;"><span style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box;">java</span><span class="" data-state="closed" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box;"><button class="flex gap-1 items-center" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; align-items: center; appearance: button; background-image: none; border-color: rgb(227, 227, 227); border-style: solid; border-width: 0px; cursor: pointer; display: flex; font-family: inherit; font-size: 12px; font-weight: inherit; gap: 0.25rem; line-height: inherit; margin: 0px; padding: 0px;"><svg class="icon-sm" fill="none" height="24" viewbox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="M12 4C10.8954 4 10 4.89543 10 6H14C14 4.89543 13.1046 4 12 4ZM8.53513 4C9.22675 2.8044 10.5194 2 12 2C13.4806 2 14.7733 2.8044 15.4649 4H17C18.6569 4 20 5.34315 20 7V19C20 20.6569 18.6569 22 17 22H7C5.34315 22 4 20.6569 4 19V7C4 5.34315 5.34315 4 7 4H8.53513ZM8 6H7C6.44772 6 6 6.44772 6 7V19C6 19.5523 6.44772 20 7 20H17C17.5523 20 18 19.5523 18 19V7C18 6.44772 17.5523 6 17 6H16C16 7.10457 15.1046 8 14 8H10C8.89543 8 8 7.10457 8 6Z" fill-rule="evenodd" fill="currentColor"></path></svg>Copy code</button></span></div><div class="p-4 overflow-y-auto" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; overflow-y: auto; padding: 1rem;"><div class="p-4 overflow-y-auto" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; overflow-y: auto; padding: 1rem;"><div style="background-color: #1e1f22; color: #bcbec4;"><pre style="font-family: 'JetBrains Mono',monospace; font-size: 11.3pt;"><span style="color: #cf8e6d;">public class </span>Calculator <span style="color: #e8ba36;">{<br /></span><span style="color: #e8ba36;"><br /></span><span style="color: #e8ba36;"> </span><span style="color: #cf8e6d;">public double </span><span style="color: #56a8f5;">calculate</span><span style="color: #e8ba36;">(</span><span style="color: #cf8e6d;">double </span><span style="color: #c77dbb; font-style: italic;">num1</span>, <span style="color: #cf8e6d;">double </span><span style="color: #c77dbb; font-style: italic;">num2</span>, <span style="color: #cf8e6d;">char </span><span style="color: #c77dbb; font-style: italic;">operator</span><span style="color: #e8ba36;">) </span><span style="color: #54a857;">{<br /></span><span style="color: #54a857;"> </span><span style="color: #cf8e6d;">switch </span><span style="color: #e8ba36;">(</span><span style="color: #c77dbb; font-style: italic;">operator</span><span style="color: #e8ba36;">) </span><span style="color: #359ff4;">{<br /></span><span style="color: #359ff4;"> </span><span style="color: #cf8e6d;">case </span><span style="color: #6aab73;">'+'</span>:<br /> <span style="color: #cf8e6d;">return </span><span style="color: #c77dbb; font-style: italic;">num1 </span>+ <span style="color: #c77dbb; font-style: italic;">num2</span>;<br /> <span style="color: #cf8e6d;">case </span><span style="color: #6aab73;">'-'</span>:<br /> <span style="color: #cf8e6d;">return </span><span style="color: #c77dbb; font-style: italic;">num1 </span>- <span style="color: #c77dbb; font-style: italic;">num2</span>;<br /> <span style="color: #cf8e6d;">case </span><span style="color: #6aab73;">'*'</span>:<br /> <span style="color: #cf8e6d;">return </span><span style="color: #c77dbb; font-style: italic;">num1 </span>* <span style="color: #c77dbb; font-style: italic;">num2</span>;<br /> <span style="color: #cf8e6d;">case </span><span style="color: #6aab73;">'/'</span>:<br /> <span style="color: #cf8e6d;">return </span><span style="color: #c77dbb; font-style: italic;">num1 </span>/ <span style="color: #c77dbb; font-style: italic;">num2</span>;<br /> <span style="color: #cf8e6d;">default</span>:<br /> <span style="color: #cf8e6d;">throw new </span>IllegalArgumentException<span style="color: #54a857;">(</span><span style="color: #6aab73;">"Invalid operator"</span><span style="color: #54a857;">)</span>;<br /> <span style="color: #359ff4;">}<br /></span><span style="color: #359ff4;"> </span><span style="color: #54a857;">}<br /></span><span style="color: #e8ba36;">}</span></pre></div></div></div></div></pre><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: #0d0d0d; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;">This class works fine for now, but what if we want to add more features to our calculator, such as trigonometric functions, logarithms, exponentiation, etc.? One option is to modify the <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-code); font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">calculate</code> method and add more cases to the switch statement. However, this would violate the OCP because we would be changing the existing code of the <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-code); font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">Calculator</code> class every time we want to extend its functionality. This would make the code more complex, error-prone, and difficult to test.</p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: #0d0d0d; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;">A better option is to follow the OCP and design the <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-code); font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">Calculator</code> class in such a way that it is open for extension but closed for modification. We can do this by using abstraction and polymorphism. Instead of having a single <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-code); font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">calculate</code> method that handles all the possible operations, we can define an abstract class or interface called <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-code); font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">Operation</code> that represents any kind of mathematical operation. The <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-code); font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">Operation</code> class or interface would have an abstract method called <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-code); font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">execute</code> that takes two numbers as parameters and returns the result of the operation. Then, we can have different subclasses or implementations of <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-code); font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">Operation</code> that represent specific operations, such as <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-code); font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">Addition</code>, <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-code); font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">Subtraction</code>, <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-code); font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">Multiplication</code>, <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-code); font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">Division</code>, <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-code); font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">Sine</code>, <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-code); font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">Cosine</code>, <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-code); font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">Logarithm</code>, <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-code); font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">Exponentiation</code>, etc. Each subclass or implementation would override the <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-code); font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">execute</code> method and provide its own logic for performing the operation. The <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-code); font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">Calculator</code> class would then have a method called <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-code); font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">calculate</code> that takes an <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-code); font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">Operation</code> object and two numbers as parameters and calls the <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-code); font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">execute</code> method of the <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-code); font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">Operation</code> object. The method would look something like this:</p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: #0d0d0d; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;"><br /></p><pre style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border-radius: 0.375rem; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; line-height: 1.71429; margin-bottom: 0px; margin-top: 0px; overflow-x: auto; padding: 0px;"><div class="dark bg-gray-950 rounded-md" style="--border-heavy: hsla(0,0%,100%,.2); --border-light: hsla(0,0%,100%,.1); --border-medium: hsla(0,0%,100%,.15); --border-xheavy: hsla(0,0%,100%,.25); --link-hover: #5e83b3; --link: #7ab7ff; --main-surface-primary: var(--gray-800); --main-surface-secondary: var(--gray-700); --main-surface-tertiary: var(--gray-600); --sidebar-surface-primary: var(--gray-900); --sidebar-surface-secondary: var(--gray-800); --sidebar-surface-tertiary: var(--gray-700); --text-primary: var(--gray-100); --text-quaternary: var(--gray-500); --text-secondary: var(--gray-300); --text-tertiary: var(--gray-400); --tw-bg-opacity: 1; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: rgba(13,13,13,var(--tw-bg-opacity)); border-radius: 0.375rem; border: 0px solid rgb(227, 227, 227); box-sizing: border-box;"><div class="flex items-center relative text-token-text-secondary bg-token-main-surface-secondary px-4 py-2 text-xs font-sans justify-between rounded-t-md" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; align-items: center; background-color: var(--main-surface-secondary); border-top-left-radius: 0.375rem; border-top-right-radius: 0.375rem; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: flex; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 0.75rem; justify-content: space-between; line-height: 1rem; padding: 0.5rem 1rem; position: relative;"><span style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box;"><span style="color: white;">java</span></span><span class="" data-state="closed" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--text-secondary);"><button class="flex gap-1 items-center" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; align-items: center; appearance: button; background-image: none; border-color: rgb(227, 227, 227); border-style: solid; border-width: 0px; cursor: pointer; display: flex; font-family: inherit; font-size: 12px; font-weight: inherit; gap: 0.25rem; line-height: inherit; margin: 0px; padding: 0px;"><svg class="icon-sm" fill="none" height="24" viewbox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="M12 4C10.8954 4 10 4.89543 10 6H14C14 4.89543 13.1046 4 12 4ZM8.53513 4C9.22675 2.8044 10.5194 2 12 2C13.4806 2 14.7733 2.8044 15.4649 4H17C18.6569 4 20 5.34315 20 7V19C20 20.6569 18.6569 22 17 22H7C5.34315 22 4 20.6569 4 19V7C4 5.34315 5.34315 4 7 4H8.53513ZM8 6H7C6.44772 6 6 6.44772 6 7V19C6 19.5523 6.44772 20 7 20H17C17.5523 20 18 19.5523 18 19V7C18 6.44772 17.5523 6 17 6H16C16 7.10457 15.1046 8 14 8H10C8.89543 8 8 7.10457 8 6Z" fill-rule="evenodd" fill="currentColor"></path></svg>Copy code</button></span></div><div class="p-4 overflow-y-auto" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; overflow-y: auto; padding: 1rem;"><div style="background-color: #1e1f22;"><pre style="font-family: "JetBrains Mono", monospace; font-size: 11.3pt;"><div style="color: #bcbec4;"><pre style="font-family: 'JetBrains Mono',monospace; font-size: 11.3pt;"><div><pre style="font-family: 'JetBrains Mono',monospace; font-size: 11.3pt;"><span style="color: #cf8e6d;">interface </span>Operation <span style="color: #e8ba36;">{<br /></span><span style="color: #e8ba36;"> </span><span style="color: #cf8e6d;">double </span><span style="color: #56a8f5;">execute</span><span style="color: #e8ba36;">(</span><span style="color: #cf8e6d;">double </span><span style="color: #c77dbb; font-style: italic;">num1</span>, <span style="color: #cf8e6d;">double </span><span style="color: #c77dbb; font-style: italic;">num2</span><span style="color: #e8ba36;">)</span>;<br /><span style="color: #e8ba36;">}<br /></span><span style="color: #e8ba36;"><br /></span><span style="color: #cf8e6d;">
public class </span>Add <span style="color: #cf8e6d;">implements </span>Operation <span style="color: #e8ba36;">{<br /></span><span style="color: #e8ba36;"> </span><span style="color: #b3ae60;">@Override<br /></span><span style="color: #b3ae60;"> </span><span style="color: #cf8e6d;">public double </span><span style="color: #56a8f5;">execute</span><span style="color: #e8ba36;">(</span><span style="color: #cf8e6d;">double </span><span style="color: #c77dbb; font-style: italic;">num1</span>, <span style="color: #cf8e6d;">double </span><span style="color: #c77dbb; font-style: italic;">num2</span><span style="color: #e8ba36;">) </span><span style="color: #54a857;">{<br /></span><span style="color: #54a857;"> </span><span style="color: #cf8e6d;">return </span><span style="color: #c77dbb; font-style: italic;">num1 </span>+ <span style="color: #c77dbb; font-style: italic;">num2</span>;<br /> <span style="color: #54a857;">}<br /></span><span style="color: #e8ba36;">}</span></pre><pre style="font-family: 'JetBrains Mono',monospace; font-size: 11.3pt;"><span style="color: #e8ba36;"><br /></span><span style="color: #cf8e6d;">public class </span>Calculator <span style="color: #e8ba36;">{<br /></span><span style="color: #e8ba36;"> </span><span style="color: #cf8e6d;">public double </span><span style="color: #56a8f5;">calculate</span><span style="color: #e8ba36;">(</span><span style="color: #cf8e6d;">double </span><span style="color: #c77dbb; font-style: italic;">num1</span>, <span style="color: #cf8e6d;">double </span><span style="color: #c77dbb; font-style: italic;">num2</span>, Operation <span style="color: #c77dbb; font-style: italic;">operation</span><span style="color: #e8ba36;">) </span><span style="color: #54a857;">{<br /></span><span style="color: #54a857;"> </span><span style="color: #cf8e6d;">return </span><span style="color: #c77dbb; font-style: italic;">operation</span>.execute<span style="color: #e8ba36;">(</span><span style="color: #c77dbb; font-style: italic;">num1</span>, <span style="color: #c77dbb; font-style: italic;">num2</span><span style="color: #e8ba36;">)</span>;<br /> <span style="color: #54a857;">}<br /></span><span style="color: #e8ba36;">}<br /></span></pre></div></pre></div></pre></div></div></div></pre><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: #0d0d0d; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;">By adopting this approach, we adhere to the Open-Closed Principle, allowing us to introduce new operations without modifying the existing code of the <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: var(--tw-prose-code); font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">Calculator</code> class. Each new operation is encapsulated in its own class, promoting maintainability, readability, and ease of extension. This design also facilitates testing, as each operation can be tested independently, contributing to a more robust and flexible system.</p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: #0d0d0d; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;">Peace,</p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: #0d0d0d; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;">JD</p>J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.com0tag:blogger.com,1999:blog-8076032851736657838.post-43409931932333038212024-03-04T10:19:00.001-05:002024-03-04T10:19:32.079-05:00 Decoding Dependency Inversion: Elevating Your Code to New Heights<p>Greetings coding enthusiasts,</p><p><br /></p><p>Today's discussion delves into the profound concept of Dependency Inversion, unraveling its mysteries and exploring how it can elevate the sophistication of your codebase.</p><p><br /></p><h3 style="text-align: left;">Unveiling the Core of Dependency Inversion</h3><p>At its essence, Dependency Inversion is a concept championed by Robert C. Martin, advocating the inversion of traditional dependency flows within a system. This principle encourages a paradigm shift where high-level modules are independent of low-level implementations, fostering a codebase that is more flexible, adaptable, and maintainable.</p><p><br /></p><h3 style="text-align: left;">The Dependency Inversion Principle (DIP)</h3><p>Situated as one of the five SOLID principles of object-oriented design, the Dependency Inversion Principle asserts two fundamental guidelines:</p><p><br /></p><p>High-level modules should not depend on low-level modules. Both should depend on abstractions.</p><p>Abstractions should not depend on details. Details should depend on abstractions.</p><p>In simpler terms, Dependency Inversion calls for a departure from the traditional structure where high-level components dictate the behavior of low-level components. Instead, both levels should depend on abstractions, paving the way for seamless modifications and extensions.</p><p><br /></p><h3 style="text-align: left;">Breaking the Shackles of Dependency Chains</h3><p>In a conventionally tightly coupled system, the rigid hierarchy of high-level modules dictating the behavior of low-level modules impedes the adaptability of the codebase. Dependency Inversion liberates the code by introducing a layer of abstraction. This abstraction allows both high-level and low-level components to depend on common interfaces, eliminating the need for direct dependencies.</p><p><br /></p><h3 style="text-align: left;">The Pivotal Role of Interfaces</h3><p>Interfaces emerge as key players in the application of Dependency Inversion. By defining interfaces that encapsulate behaviors, high-level modules can interact with low-level modules through these abstractions. This indirection facilitates communication through well-defined contracts, reducing dependencies on specific implementations.</p><p><br /></p><h3 style="text-align: left;">Practical Implementation of Dependency Inversion</h3><p>Consider the common scenario of database access in a web application. Rather than high-level business logic tightly coupling with a specific database implementation, Dependency Inversion advocates creating an interface (e.g., DatabaseRepository). Concrete implementations (such as MySQLRepository or MongoDBRepository) adhere to this interface, allowing the high-level logic to interact with any database without direct dependencies.</p><p><br /></p><p>Unlocking the Benefits of Dependency Inversion</p><p>Flexibility and Adaptability: Dependency Inversion decouples components, providing the freedom to switch out implementations without disrupting the overall system.</p><p><br /></p><p>Testability: Abstracting dependencies through interfaces simplifies testing, allowing for the use of mock implementations and ensuring the isolation of units during testing.</p><p><br /></p><p>Reduced Coupling: Dependency Inversion reduces the coupling between different parts of your code, fostering a modular and maintainable codebase.</p><p><br /></p><p>Parting Thoughts</p><p>In embracing Dependency Inversion, we empower our code to gracefully adapt to change and evolve over time. Adherence to the Dependency Inversion Principle molds architectures that are resilient, testable, and inherently scalable.</p><p><br /></p><p>As you navigate the intricate landscapes of software design, consider the transformative influence of Dependency Inversion. May your abstractions be robust, and your dependencies, elegantly inverted.</p><p><br /></p><p>Happy coding!</p><p>JD</p><p>Cheers,</p>J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.com0tag:blogger.com,1999:blog-8076032851736657838.post-30346723854254881492024-03-04T10:04:00.000-05:002024-03-04T10:04:02.428-05:00Unraveling Hexagonal Architecture: A Blueprint for Code Harmony<p><span style="background-color: white;"><span style="font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; white-space-collapse: preserve;">Hello fellow developers,</span></span></p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;"><span style="background-color: white;">Today, let's delve into the captivating realm of Hexagonal Architecture. As software craftsmen, we're constantly seeking design paradigms that not only make our code maintainable but also allow it to evolve gracefully with changing requirements. Enter Hexagonal Architecture, also known as Ports and Adapters.</span></p><h3 style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 1.25em; line-height: 1.6; margin: 1rem 0px 0.5rem; white-space-collapse: preserve;"><span style="background-color: white;">Understanding the Hexagon</span></h3><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 0px 0px 1.25em; white-space-collapse: preserve;"><span style="background-color: white;">At its core, Hexagonal Architecture revolves around the concept of a hexagon – a shape with six equal sides, each representing a facet of your application. This model focuses on decoupling the core business logic from external concerns, resulting in a more flexible and testable system.</span></p><h3 style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 1.25em; line-height: 1.6; margin: 1rem 0px 0.5rem; white-space-collapse: preserve;"><span style="background-color: white;">The Hexagon's Heart: The Core</span></h3><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 0px 0px 1.25em; white-space-collapse: preserve;"><span style="background-color: white;">Picture the hexagon's center as the heart of your application – the core business logic. This is where the magic happens, where your unique value proposition resides. It's independent of external details such as databases, frameworks, or UI elements. Here, your business rules reign supreme.</span></p><h3 style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 1.25em; line-height: 1.6; margin: 1rem 0px 0.5rem; white-space-collapse: preserve;"><span style="background-color: white;">Ports and Adapters: The Boundary</span></h3><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 0px 0px 1.25em; white-space-collapse: preserve;"><span style="background-color: white;">The sides of the hexagon represent the application's boundaries. We have "ports" for interacting with the outside world and "adapters" for implementing those ports. Ports define interfaces through which the core communicates, while adapters provide concrete implementations, bridging the gap between the core and external components.</span></p><h4 style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; font-weight: 400; line-height: 1.5; margin: 1rem 0px 0.5rem; white-space-collapse: preserve;"><span style="background-color: white;">Adapting to the Real World</span></h4><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 0px 0px 1.25em; white-space-collapse: preserve;"><span style="background-color: white;">Consider an example where your application needs to persist data. Instead of embedding database code directly into the core, you create a port, say <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">PersistencePort</code>, defining methods like <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">save</code> and <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace !important; font-size: 0.875em; font-weight: 600;">retrieve</code>. Adapters, then, implement this port – one adapter for a relational database, another for a document store, and so on.</span></p><h3 style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 1.25em; line-height: 1.6; margin: 1rem 0px 0.5rem; white-space-collapse: preserve;"><span style="background-color: white;">Embracing Dependency Inversion</span></h3><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 0px 0px 1.25em; white-space-collapse: preserve;"><span style="background-color: white;">Hexagonal Architecture thrives on the Dependency Inversion Principle. Rather than depending on concrete implementations, the core defines interfaces (ports) that external components (adapters) implement. This inversion of control empowers the core, reducing its reliance on volatile external details.</span></p><h3 style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 1.25em; line-height: 1.6; margin: 1rem 0px 0.5rem; white-space-collapse: preserve;"><span style="background-color: white;">Hexagonal Harmony in Action</span></h3><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 0px 0px 1.25em; white-space-collapse: preserve;"><span style="background-color: white;">Let's visualize this with a scenario. Imagine your application is a bakery management system. The core handles crucial bakery operations, like creating recipes and managing inventory. On one side, you have a UI adapter allowing interaction through a sleek web interface. On another side, a persistence adapter ensures your recipes endure, be it in a relational database or a cloud-based storage solution.</span></p><h3 style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 1.25em; line-height: 1.6; margin: 1rem 0px 0.5rem; white-space-collapse: preserve;"><span style="background-color: white;">Benefits Beyond Symmetry</span></h3><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 0px 0px 1.25em; white-space-collapse: preserve;"><span style="background-color: white;">The advantages of Hexagonal Architecture extend far beyond its elegant symmetry. Your code becomes more modular, promoting easier maintenance and testing. The core remains blissfully unaware of the external forces acting upon it, fostering adaptability to changes without jeopardizing the essence of your application.</span></p><h3 style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 1.25em; line-height: 1.6; margin: 1rem 0px 0.5rem; white-space-collapse: preserve;"><span style="background-color: white;">Parting Thoughts</span></h3><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 0px 0px 1.25em; white-space-collapse: preserve;"><span style="background-color: white;">In the grand tapestry of software design, Hexagonal Architecture stands as a testament to elegance and adaptability. Embrace the hexagon, where your core business logic resides, surrounded by ports and adapters that dance in harmony, ensuring your application's longevity in an ever-evolving digital landscape.</span></p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;"><span style="background-color: white;">Until next time, happy coding!</span></p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px 0px; white-space-collapse: preserve;"><span style="background-color: white;">Cheers,
JD</span></p>J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.com0tag:blogger.com,1999:blog-8076032851736657838.post-65485427065519760082022-02-18T06:26:00.001-05:002022-02-18T06:26:28.937-05:00Ports and Adapters, Part 2<h1 style="text-align: left;">Ports and Adapters part 2</h1><h2 style="text-align: left;">Approach, not reproach</h2><div>Many programming tutorials are difficult to follow. I do not necessarily expect this one to be any different, but I'll try. I'm going to start with relatively broad concepts, any of which may lead to a new post drilling down into that topic in further detail one day.</div><h3 style="text-align: left;">Take a client-centric view of the solution</h3><div>We have nobody to blame but ourselves. We've all done it. You hit Google, or StackOverflow, and you grab a chunk of code that interfaces with some library we want to use. Then we change the shape of our code, introducing abstractions that don't really gel that well with the ones around it, in order to make that adopted code work.</div><div>Don't do that.</div><h3 style="text-align: left;">Design the API you want to use</h3><div>Think about things from your own application's point of view. Do you need a database client? Or do you need a way to get data based on a few 'key' criteria? What level of abstraction do you really want to be working with as you write your code?</div><h3 style="text-align: left;">Test first</h3><div>I prefer a TDD (Test Driven Development) approach to writing code. When one first encounters the notion, it seems backwards. It was certainly very different from practices I'd spent years on. But in the end, following this discipline beats the hell out of attempting to add unit tests to the tangled messes many of us naturally weave otherwise. I've been called good (or sometimes better than that) at what I do, but when I look around at my code, what I see is still more of a mess than I'd like.</div><div>TDD really helps with that. I think that topic deserves a post of its own.</div><div>Use your concept to build some code. Mock the responses you intend your own API to provide. Call your own API. It's all a kind of unit/integration testing hybrid, it's all provably correct. It also works the way you think as a developer, long before you've actually decided which database or messaging system you'll be using.</div><h3 style="text-align: left;">Adapt your concept to a real-world library</h3><div><div>When you've achieved that level, it's finally time to replace the mocked service provider with a real one... And testing that can appear very difficult. I'll discuss techniques for that in future posts.</div></div><div><br /></div><div>But first, a word about using code that demonstrates use of a library:</div><div><br /></div><div>There's nothing wrong with learning how to use a library that way. It should teach you the general usage patterns, pre-requisites, etc. But that doesn't mean you should copy that demo function into your production application and start to use it!</div><div><br /></div><div>At a bare minimum paste it into a new source file. Better yet, use a test-driven approach to create a new file that implements the subset of capabilities you need.</div><div>Enjoy!</div><div><br /></div><div>That's really all you have to do to get dependencies out of your own code. It sounds easy, and sometimes it is. Actually, a lot of the time it is, once you figure out how to think about it.</div><div><br /></div>J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.com0tag:blogger.com,1999:blog-8076032851736657838.post-34730695838965744922022-01-31T14:56:00.009-05:002022-01-31T14:57:40.481-05:00Ports and Adapters part 1<h1 style="text-align: left;">Ports and Adapters part 1</h1><h2 style="text-align: left;">A love story</h2><p>Today I want to begin a series about a technique which has helps to isolate code from changes in implementation details. Sometimes those details may seem central to the code in question, but many times it just isn't.</p><p>I'm going to start with a little story. I don't know if it's interesting or not, but it's all true.3</p><p>Many years ago, back when my razor stubble was brown and I was a hired gun programmer, I was responsible for maintaining a corporate security library. This was an important library. Dozens of applications depended on it to authenticate and authorize corporate users.</p><p>There's just one problem: It relied on an obsolete LDAP library which was no longer being maintained, and that had to change.</p><p>This was a pretty frightening task. It absolutely had to work. This was before the idea of providing such a thing as a service had become popular, and the library was statically linked to all those applications. A mistake meant a patch, a patch that would get attention, and what's more a patch that would have to be quickly rolled out to all affected applications.</p><p>I hate attention. Well, bad attention anyway. I suppose I'm also not really a big fan of emergency deployments. </p><p>I had to formulate a plan of attack. As per my usual practice, I banged my head against things until I eventually worked out what I could have found in a book. Let me walk you through my process:</p><h3 style="text-align: left;">Step 1: Tests</h3><p>First, I built a comprehensive suite of unit tests that validated all of the library's functions. The tests were a little more integration-ey than I would build today, but when things were green? I had great confidence that I would have a successful build. We were also adopting Jenkins at the time, so every code commit was tested and built automatically.</p><h3 style="text-align: left;">Step 2: Isolation</h3><p>Next up, I isolated all of the library calls behind interfaces. That was a lot of effort, but with the tests backing me up, I was able to keep everything working just as before. I did have to add a factory to instantiate the main library class, but kept that hidden behind a facade that looked unchanged to the API users. </p><h3 style="text-align: left;">Step 3: In with the new</h3><p>Now I started on the new code. By sticking to the interfaces which allowed me to accomplish step 2, I was able to swap back and forth between the fully functional production implementation and the one under development. All I had to do was change the name of the class from 'new obsoleteImplemenation()' to 'new unfinishedImplementation()'. I could run the test suite and get a pretty solid idea of how far I had come and how far I had to go.</p><h3 style="text-align: left;">Step 4: Risky business</h3><p>I realized that this was dangerous territory. If I shipped a library that had an unexpected bug under load or under some kind of unexpected error condition, there could be really big implications. The user base included both internal and external entities, offering lots of exposure. That was too big a risk, so I had to do something to mitigate it.</p><h3 style="text-align: left;">Step 5: On reflection, this is a good idea</h3><p>I was working in Java, so I decided to take advantage of <i>reflection</i> to create the class. If you aren't familiar with the concept, it is just a way of creating an object using the name of the class as a string value. That came in handy, because now I could just have the two different class names for the now-isolated library and use either one live at run-time. To make it as safe as possible, I initially defaulted to the old library, but gave the clients an option to set an environment variable to enable the new one.</p><p>Fortunately, I had good ties with developers for several of the other projects, and I was able to cajole them into testing and then deploying with the optional library enabled.</p><h3 style="text-align: left;">Step 6: Once more into the breach</h3><p>Once I had good feedback, I felt safe making the new library the default, while allowing an environment variable to enable the <i>old</i> library. I kept that around for a good long while, until I was sure it was safe to get rid of it.</p><h1 style="text-align: left;">Phew</h1><p>That was a lot of effort and a lot of worry as well. We can do a little better than this. In fact, we can do a great deal better than this, although frankly I was proud of my accomplishment. What I'd stumbled into was a more general idea around dependency isolation. You'll hear terms like 'hexagonal architecture' used to tell you what to do. </p><p>But how do you actually DO it?</p><p>That's what I want to talk into in the next few posts. Swapping dependencies can be a giant pain point, but <i>it does not have to be</i>. The most difficult thing, really, is adapting how you think about systems. The trick is to stop trying to adapt our code to someone else's idea of how an API should work. That is OK for quick demonstrations or tutorials, but it's not how I believe we should build systems.</p><p>Instead, when we require a capability, we should design an API for that capability ourselves, whether or not we intend to implement it. The design should be harmonious with our existing system, or at least follow similar conventions. It should not feel tacked on.</p><p>Integrating external libraries deeply into our own code base is a code smell. I want my code talking to my own libraries, which will act as <i>adapters</i> to the third party code I want or need to use. Let those adapters have the weird stuff that thinks the way other people do. My job is to make those adapters conform to the expectations I've set for/with my API design.</p><p>Next time around, I'll dig a little deeper into what I mean by designing an API ourselves, and what the benefits (and costs) are.</p><p>Peace,</p><p>JD</p>J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.com0tag:blogger.com,1999:blog-8076032851736657838.post-72105737271751675072022-01-28T05:38:00.002-05:002022-01-28T05:38:09.631-05:00Check in, check out, Daniel-sanWhen you start to work on projects with more than one developer, you suddenly find yourself having to solve what sounds like a very simple problem: Sharing code. At its heart it IS simple, but the reality is that you have to take a disciplined approach. Trying to do this without using a tool designed for the job is a likely path to madness, and it's a bit mad not to do so given that the tools you need are widely available at no cost. Every professional shop, open source project and even many independent individuals makes use of some kind of <i>version control system</i>.<br />
<br />
Version control at first feels like a burden. If anything though, it is quite the opposite. Knowing that your old code is out there, ready to be brought back into your project anytime you need it? That's gold. It frees you up to experiment, to explore, to go down paths that you really aren't sure lead anywhere.<br />
<br />
So how does one get started? Naturally, as with anything else, it begins with education and access. In this case, you need to determine what you have available to you first. If there's an existing system ready for you to use, you probably want to take advantage of that. If you're a clean slate, you need to get something set up. There are many services out there which provide version control, and it can even be free if you don't have a problem with other people possibly seeing your code. It can also be free if you feel safe just running everything on your own computer or a server you control, although then you may need to install a service and keep it running.<br />
<br />
Here are some of the more popular version control systems:<br />
<br />
CVS - An old standby, it still works but frankly it's lacking a bit in features more modern systems have.<br />
SVN - More modern and quite functional, I have worked (and continue to do so) in subversion shops for years.<br />
Bitkeeper - This was paid software for years and I've never actually used it myself . It basically came about as an answer to the difficulties Linus Torvalds was having with Linux development.<br />
Git - A slightly more convoluted system than some, but clearly very powerful. This ALSO came about due to Linux development, and apparently due to issues Linus was having with Bitkeeper.<br />
<br />
There are others, but these are probably the main ones most of you will be looking at.<br />
<br />
I personally use Git (hosted on a service) for code I share on this blog and for my own experimental work. It doesn't cost me anything, and it's nicely integrated with my IntelliJ IDE. It also supports something called a 'gist', which is (as far as I know) a unique way to share a subset of a project in order to request assistance or provide examples.<br />
<br />
The basic idea behind version control is the same, no matter what system you use. Your make changes to software on your own computer and make sure that things work the way you want. When you're happy with the code, you check it in to your version control repository. If you are unhappy with the code, or have broken something to the point where fixing it is a major burden, you can just pull the last working copy back down and you're back to a known good starting point.<br />
<br />
If multiple programmers are working on a project, things are much the same, except that you will pull the last working copy down a bit more often as you are getting all the changes that others have checked in as well. Things are quite simple as long as two developers aren't working on the same exact files. If they are working on the same files, some manual intervention is likely going to be needed to ensure that changes don't conflict. That last process is called 'merging'.<br />
<br />
<br />Merging is a source of difficulty, or it can be, depending on your development practices. I prefer to keep commit changes small and isolated whenever possible. This keeps the differences (deltas) down to manageable levels, and if I've added two new source files rather than modified an existing one, we're not going to run into any problems.J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.com0tag:blogger.com,1999:blog-8076032851736657838.post-3757953396517898672022-01-28T05:13:00.001-05:002022-01-28T05:13:23.017-05:00Avoiding the Deadly QuadrantI saw a <a href="https://www.youtube.com/watch?v=UJrmee7o68A" target="_blank">video</a> (opens in a new window) recently which illustrated an important concept in a very elegant way. <br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-3AxkTant0sw/XkkqCt6skhI/AAAAAAAAXFE/TJv3gQ8C8goGk-jfPfA6UgXLR4XmGZpawCLcBGAsYHQ/s1600/Mutability%2Bvs%2Bshared.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="906" data-original-width="1600" height="361" src="https://1.bp.blogspot.com/-3AxkTant0sw/XkkqCt6skhI/AAAAAAAAXFE/TJv3gQ8C8goGk-jfPfA6UgXLR4XmGZpawCLcBGAsYHQ/s640/Mutability%2Bvs%2Bshared.jpg" width="640" /></a></div>
<br />
<br />
This is important, because in 3/4 of this diagram, your code is inherently safe to run in a multi-threaded environment. There are no synchronization blocks required, there is no need for complicated gatekeeping. And yet, somehow a lot of code winds up with mutable data and synchronization headaches.<div><br /></div><div>Applying just a few functional programming principles to your work can go a long way. Parameters should generally be considered inviolate, use return properly and don't try modifying your inputs directly. Prefer constants to variables. </div><div><br /></div><div>When you kick off a process, you really don't want it randomly reaching out and modifying some kind of global state. If it REALLY needs to send messages home, give it a tool to do so, such as a callback function it can use for that purpose.</div>J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.com0tag:blogger.com,1999:blog-8076032851736657838.post-38218468478588258622022-01-28T05:08:00.002-05:002022-01-28T05:08:17.722-05:00New Directions<p> I've been learning lately.</p><p>I mean, I have been learning a lot. Some of it is completely new, some of it is just fresh perspective on old ideas.</p><p>This is undoubtedly the natural consequence of being put in charge of developing a green-field project (can you believe it?!?) using both familiar and unfamiliar technologies. It's a mobile app. It's an API. It's a cloud native, event driven... work in progress. As a consequence, I run into unexpected things all the time. I also get to see up close what works and doesn't, as my client is flexible enough to let us experiment with features.</p><p>I think I need to record this stuff for anyone who might be interested. I'm not saying that I will be giving up on discussions of OOP principles, but I will also be expanding my reach.</p><p>There was no single trigger for this, but the past year or so has helped me to understand a few new tools and concepts. I'm still working out others, as I have been all along. But now I'm going to write it down here.</p><p>I hope it proves useful.</p><p><br /></p><p>JD</p>J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.com0tag:blogger.com,1999:blog-8076032851736657838.post-73521932590622495762020-02-15T06:02:00.004-05:002020-02-15T06:02:39.557-05:00Mary had a little lambdaJava 8 brought a lot of changes to the imperative/object oriented world of corporate software development. So many changes that to this day the more fluent and functional style of code this enables is still not as prevalent as one might hope.<br />
<br />
Today I'm going to discuss one aspect of these changes, <i>lambda expressions</i>.<br />
<br />
What is a lambda? It's a function without a name, and with an initially odd looking syntax.<br />
<br />
When you see something that looks like this:<br />
<pre style="background-color: #131314; color: #ebebeb; font-family: consolas; font-size: 15pt;"><span style="color: #7ec3e6;">.map(t->t.getModels())</span></pre>
<div>
<span style="color: #7ec3e6;"><br /></span></div>
You may get a bit confused. I know I did, and it took me a little while to comprehend this structure.<br />
<br />
But really, it's just creating a method call with slightly different syntax. When written with a bit of the fluff left in it may start to look rather familiar:<br />
<br />
<pre style="background-color: #131314; color: #ebebeb; font-family: consolas; font-size: 15pt;"><span style="color: #7ec3e6;">map((t)->t.getModels())</span></pre>
<div>
<span style="color: #7ec3e6;"><br /></span></div>
Or<br />
<pre style="background-color: #131314; color: #ebebeb; font-family: consolas; font-size: 15pt;"><span style="color: #7ec3e6; font-size: 15pt;">map((t)->{ return t.getModels(); })</span></pre>
<div>
<br />
These all do the same thing. This is a method, one designed to do only one thing, return the models contained within the parameter object passed to it. The big difference is that there's no name for the method and we've added a little '->' to indicate that it's not to be executed now but at need. That is what makes it a lambda, mostly. It is a method or function, but one which can be passed around to whoever might be interested in it, but whether or not it runs depends on if the program needs results from it. </div>
<div>
<br /></div>
<div>
Note that you would probably never write this as a stand-alone method. You already have a one-liner in whatever 't' represents. </div>
<div>
<br /></div>
<div>
And that "whatever 't' represents" is one of the issues that can make it a little harder than it has to be to understand. I don't love one letter variable names, so maybe it would be more straightforward to write it like this:</div>
<div>
<br /></div>
<div>
<pre style="background-color: #131314; color: #ebebeb; font-family: consolas; font-size: 15pt;"><span style="color: #7ec3e6;">.map(manufacturer->manufacturer.getModels())</span></pre>
</div>
<div>
<span style="color: #7ec3e6;"><br /></span></div>
<div>
<div>
I haven't seen that done very often, but I'm going to go this way for my own work because it expresses the intention with perfect clarity. Sure, in IntelliJ I get hints along the right side of the screen that inform me about types, but what about a code snippet from GitLab or something?</div>
<div>
<br /></div>
<div>
There is one additional thing you absolutely must understand about lambda expressions: Everything you hand to one has to remain unchanged until the thing actually executes. If you try to put a mutable variable in there you're gonna have a bad time. <b>Only </b>the parameter(s) can be different from call to call. </div>
<div>
<br /></div>
<div>
Finally, there can be a temptation (especially given the syntax of that third example) to stick a few more lines of code inside the brackets. Don't do that. If it is a unit or work, it's worth naming it and making it available to others. Extract a method and call that instead. I almost wish that we couldn't write things that way, because programmers tend to be... Oh, let's say <i>expedient</i> about getting things done. I completely understand that, but please don't do this:</div>
<div>
<br /></div>
<div>
<pre style="background-color: #131314; color: #ebebeb; font-family: consolas; font-size: 15pt;"><span style="color: #7ec3e6;">.map(manufacturer-> {</span></pre>
<pre style="background-color: #131314; font-family: consolas; font-size: 15pt;"><span style="color: #7ec3e6;"> if (manufacturer.getName.equals("blahblah") {</span></pre>
<pre style="background-color: #131314; font-family: consolas; font-size: 15pt;"><span style="color: #7ec3e6;"> doSomething();</span></pre>
<pre style="background-color: #131314; font-family: consolas; font-size: 15pt;"><span style="color: #7ec3e6;"> } else {</span></pre>
<pre style="background-color: #131314; font-family: consolas; font-size: 15pt;"><span style="color: #7ec3e6;"> doSomethingElse();</span></pre>
<pre style="background-color: #131314; font-family: consolas; font-size: 15pt;"><span style="color: #7ec3e6;"> }</span></pre>
<pre style="background-color: #131314; font-family: consolas; font-size: 15pt;"><span style="color: #7ec3e6;"> logger.info("Hey, look, I'm screwing up lambdas for all!");</span></pre>
<pre style="background-color: #131314; color: #ebebeb; font-family: consolas; font-size: 15pt;"><span style="color: #7ec3e6;"> return manufacturer.stream()</span></pre>
<pre style="background-color: #131314; color: #ebebeb; font-family: consolas; font-size: 15pt;"><span style="color: #7ec3e6;"> .collect(asList(manufacturer.getModels()));</span></pre>
<pre style="background-color: #131314; color: #ebebeb; font-family: consolas; font-size: 15pt;"><pre style="color: black; font-family: consolas; font-size: 15pt;"><span style="color: #7ec3e6;"> }</span></pre>
</pre>
</div>
</div>
<div>
<br /></div>
<div>
Just don't. If it deserves curly braces, it deserves a name. </div>
J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.com1tag:blogger.com,1999:blog-8076032851736657838.post-47892684328296293442020-01-12T07:51:00.002-05:002020-01-12T07:51:59.124-05:00GitLab migrationBeginning today (January 12, 2020) OOP University will be migrating all version control activity to GitLab. All new or updated code samples will be found at <a href="https://gitlab.com/oop-university" target="_blank">https://gitlab.com/oop-university</a>.<br />
<br />
I am thinking of doing some tutorials on some more peripheral topics such as continuous integration pipelines. While not directly related to OOP, we need to have a grasp on these topics as software developers.J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.com0tag:blogger.com,1999:blog-8076032851736657838.post-79647941092991773252018-03-20T10:13:00.001-04:002018-03-27T12:33:56.177-04:00Lets give Spring the Boot<script async="" src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<script>
(adsbygoogle = window.adsbygoogle || []).push({
google_ad_client: "ca-pub-7657469063489944",
enable_page_level_ads: true
});
</script>
Hi folks. It's been a while since I've posted anything here. Let's just say that life is complicated.<br />
<br />
I was inspired to write this based on some recent experiences with <i>Spring Boot</i>. This is a very powerful technology that relies on Spring and takes it to new and interesting places. The bottom line is that while there are many ways to structure a system, if we pick one and stick with it we see some real benefits. Productivity improves, communication between developers is facilitated, and some really cool automation can be brought to bear on the task of building a system.<br />
<br />
So what IS Spring Boot? It's really a few classes and conventions wrapped around Spring that frees the developer from a lot of the grunt work that used to be required. For instance, the need for xml configuration files has been essentially eliminated. Can I get an amen? There is a lot more to it, but why don't we just dig in and create a simple application?<br />
<br />
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-family: 'Consolas'; font-size: 15.0pt;"><span style="color: #cc7832;">package </span>com.oopuniversity.hellospringboot<span style="color: #cc7832;">;</span><span style="color: #cc7832;">
</span><span style="color: #cc7832;">import </span>org.springframework.boot.SpringApplication<span style="color: #cc7832;">;</span><span style="color: #cc7832;">import </span>org.springframework.boot.autoconfigure.<span style="color: #bbb529;">SpringBootApplication</span><span style="color: #cc7832;">;</span><span style="color: #cc7832;">
</span><span style="color: #bbb529;">@SpringBootApplication</span><span style="color: #cc7832;">public class </span>App {
<span style="color: #cc7832;">public static void </span><span style="color: #ffc66d;">main</span>(String args[]) {
<span style="color: #cc7832;"> </span>SpringApplication.<span style="font-style: italic;">run</span>(App.<span style="color: #cc7832;">class, </span>args)<span style="color: #cc7832;">;</span><span style="color: #cc7832;"> </span>}
}</pre>
<br />
There you have it. A complete application which does nearly nothing... And yet it's really got a lot going on inside of it. This will actually create an application server listening (by default) on port 8080.<br />
<br />
If we run this program we will see output like this:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;"> . ____ _ __ _ _</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;"> /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;"> \\/ ___)| |_)| | | | | || (_| | ) ) ) )</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;"> ' |____| .__|_| |_|_| |_\__, | / / / /</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;"> =========|_|==============|___/=/_/_/_/</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;"> :: Spring Boot :: (v2.0.0.RELEASE)</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">2018-03-19 20:08:06.184 INFO 248504 --- [ main] com.oopuniversity.hellospringboot.App : Starting App on Razer-Laptop with PID 248504 (C:\Users\jd\workspace\basics\hello-spring-boot\build\classes\java\main started by jd in C:\Users\jd\workspace\basics)</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">2018-03-19 20:08:06.186 INFO 248504 --- [ main] com.oopuniversity.hellospringboot.App : The following profiles are active: development</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">2018-03-19 20:08:06.225 INFO 248504 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6a01e23: startup date [Mon Mar 19 20:08:06 EDT 2018]; root of context hierarchy</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">2018-03-19 20:08:07.349 INFO 248504 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">2018-03-19 20:08:07.386 INFO 248504 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">2018-03-19 20:08:07.386 INFO 248504 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.28</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">2018-03-19 20:08:07.398 INFO 248504 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [C:\Program Files\Java\jdk1.8.0_152\bin;C:\WINDOWS\Sun\Java\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\ProgramData\Oracle\Java\javapath;C:\Program Files (x86)\Razer Chroma SDK\bin;C:\Program Files\Razer Chroma SDK\bin;C:\Program Files (x86)\Intel\iCLS Client\;C:\Program Files\Intel\iCLS Client\;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\IPT;C:\Program Files\Intel\Intel(R) Management Engine Components\IPT;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Users\Administrator\AppData\Local\Microsoft\WindowsApps;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\Program Files\PuTTY\;C:\ProgramData\chocolatey\bin;c:\bin;c:\bin\flyway-5.0.6;C:\Program Files\MySQL\MYSQL Server 5.7\bin;C:\Program Files\MySQL\MySQL Utilities 1.6\;C:\Program Files\Git\cmd;C:\Program Files\Git\mingw64\bin;C:\Program Files\Git\usr\bin;C:\Program Files\Amazon\AWSCLI\;C:\Program Files (x86)\Graphviz2.38\bin;C:\Ruby24-x64\bin;C:\Users\jd\AppData\Local\Microsoft\WindowsApps;C:\Users\jd\apache-maven-3.5.2\bin;;.]</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">2018-03-19 20:08:07.500 INFO 248504 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">2018-03-19 20:08:07.500 INFO 248504 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1277 ms</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">2018-03-19 20:08:07.606 INFO 248504 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Servlet dispatcherServlet mapped to [/]</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">2018-03-19 20:08:07.609 INFO 248504 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">2018-03-19 20:08:07.609 INFO 248504 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">2018-03-19 20:08:07.610 INFO 248504 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">2018-03-19 20:08:07.610 INFO 248504 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">2018-03-19 20:08:07.898 INFO 248504 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6a01e23: startup date [Mon Mar 19 20:08:06 EDT 2018]; root of context hierarchy</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">2018-03-19 20:08:07.967 INFO 248504 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">2018-03-19 20:08:07.969 INFO 248504 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">2018-03-19 20:08:07.993 INFO 248504 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">2018-03-19 20:08:07.993 INFO 248504 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">2018-03-19 20:08:08.024 INFO 248504 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">2018-03-19 20:08:08.131 INFO 248504 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">2018-03-19 20:08:08.162 INFO 248504 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">2018-03-19 20:08:08.164 INFO 248504 --- [ main] com.oopuniversity.hellospringboot.App : Started App in 2.244 seconds (JVM running for 2.621)</span><br />
<br />
That's really am amazing amount of output for what appears to be a one-liner, isn't it? One of the beautiful things about Spring Boot (and Spring in general) is that it is well documented internally and tells you what it's doing. Perhaps more importantly it's really good about telling you what went wrong, which is pretty much an inevitability.<br />
<br />
Since no URIs are defined, it won't actually serve up any pages as written, but you can tell it's doing at least something by hitting it with a browser.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-vQZpol4LDSw/WrD5P5b3WmI/AAAAAAAASR4/W11W8Zzte-cbzLK_7hgLdP-QsFJtCL9cQCLcBGAs/s1600/2018-03-20.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="470" data-original-width="889" height="169" src="https://2.bp.blogspot.com/-vQZpol4LDSw/WrD5P5b3WmI/AAAAAAAASR4/W11W8Zzte-cbzLK_7hgLdP-QsFJtCL9cQCLcBGAs/s320/2018-03-20.png" width="320" /></a></div>
Spring Boot is incredibly well suited to today's world of cloud-native applications built as micro-services. An application such as this really doesn't need anything more than a functional JVM to be spun up as one instance or a hundred. Everything it really requires to run can be bundled into a single .jar file and distributed where needed. There's no more hassle with deploying application servers and the attendant configuration and devops challenges.<br />
<br />
Let's add some functionality to this little program, so that it actually does a task for us. We're going to build a RESTful calculator. If you aren't familiar with RESTful services you can go look up what I'm talking about, but in short RESTful services are stateless web-based services that accept parameters in a URL and return usable responses to whoever calls them. This allows for amazing levels of integration, and every task can be built using the technology best suited for it.<br />
<br />
Since this is really just a technology demonstrator, I will not be building any of this using best practices for project layout and the like. All of that is ultimately important but unnecessary for the purpose of this post.<br />
<br />
Let's start with adding two numbers. As this will be a RESTful service, everything needed to perform the math must be specified on the URL. I will define it like this:<br />
<br />
/add/<i>number1</i>/<i>number2</i><br />
<i><br /></i>
That way, all I should really need to do to add 1 and 1 is call "http://localhost:8080/add/1/1"<br />
<br />
Doing this is really very easy. First, I need to inform Spring Boot that I want to serve up RESTful responses. In the real world I'd create a new class (or several of them) for this purpose, but for now I'll just add it to the same little program.<br />
<br />
<a href="http://3.bp.blogspot.com/-D3KRRBbgGpY/WrD-tmtCg5I/AAAAAAAASSM/JINSvrRD4EMexjPn7DEdtpMrKhjcHfghACK4BGAYYCw/s1600/RestControllerAnnotation.png" imageanchor="1"><img border="0" height="96" src="https://3.bp.blogspot.com/-D3KRRBbgGpY/WrD-tmtCg5I/AAAAAAAASSM/JINSvrRD4EMexjPn7DEdtpMrKhjcHfghACK4BGAYYCw/s640/RestControllerAnnotation.png" width="640" /></a><br />
<br />
That's straightforward enough. Now we have to put in the code to do the math:<br />
<br />
First we will need to add a couple of supporting imports:<br />
<br />
<a href="http://1.bp.blogspot.com/-5WlcdIlCpBw/WrD_egR0eCI/AAAAAAAASSY/K7p08uZH9JAULmT-_AYvWE_WpizzuJXjwCK4BGAYYCw/s1600/RESTful%2Bimports.png" imageanchor="1"><img border="0" height="58" src="https://1.bp.blogspot.com/-5WlcdIlCpBw/WrD_egR0eCI/AAAAAAAASSY/K7p08uZH9JAULmT-_AYvWE_WpizzuJXjwCK4BGAYYCw/s640/RESTful%2Bimports.png" width="640" /></a><br />
<br />
And then we're ready to craft a working service:<br />
<br />
<a href="http://3.bp.blogspot.com/-scUtTZ1qNy0/WrD_keOPoLI/AAAAAAAASSg/bHjwajo10TAlV3ayB1Ht-owLSZmiJmavACK4BGAYYCw/s1600/RESTful%2Badd.png" imageanchor="1"><img border="0" height="76" src="https://3.bp.blogspot.com/-scUtTZ1qNy0/WrD_keOPoLI/AAAAAAAASSg/bHjwajo10TAlV3ayB1Ht-owLSZmiJmavACK4BGAYYCw/s640/RESTful%2Badd.png" width="640" /></a><br />
<br />
The '@RequestMapping' annotation sets up a URI with embedded variables that will be used to invoke our new service. The @PathVariable annotation ties the embedded variables to the parameter list for our method.<br />
<br />
Believe it or not, that's all we need to get this working:<br />
<br />
<a href="http://2.bp.blogspot.com/-po0TJDIzvjE/WrEAHoZcN7I/AAAAAAAASSw/QfsO-tN1zL8v7_D5oEC-wLt5PSpS3-qlwCK4BGAYYCw/s1600/RESTful%2Badd%2Bpage.png" imageanchor="1"><img border="0" height="128" src="https://2.bp.blogspot.com/-po0TJDIzvjE/WrEAHoZcN7I/AAAAAAAASSw/QfsO-tN1zL8v7_D5oEC-wLt5PSpS3-qlwCK4BGAYYCw/s320/RESTful%2Badd%2Bpage.png" width="320" /></a><br />
<br />
As you can imagine, it's as straightforward as can be to extend this to additional operations.<br />
<br />
I will leave it as an exercise for the reader to add more operations to this. It's very straightforward and you really shouldn't have any problems doing so.<br />
<br />
That's about it for now. Have fun!<br />
<br />
<br />
<br />
<br />J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.com0tag:blogger.com,1999:blog-8076032851736657838.post-84293581921422717572016-06-11T08:39:00.001-04:002016-06-12T08:45:04.870-04:00Basics: Just what IS an object, anyway?This is a pretty long one by the standards of this blog. Try to stay with it, though, the concepts are crucial.<br />
<br />
Whether people are experienced developers used to procedural languages or newcomers to programming in general, really understanding objects tends to be a bit of a sticking point. It's odd, because once you start to get it, everything seems quite natural.<br />
<div>
<br /></div>
<div>
An object is a representation of... something. Sometimes they represent fairly nebulous concepts, sometimes they represent very real physical things, but in all cases they're a kind of model. Objects have <i>properties</i>, just like a flower has a color or a bee has [6] legs. Objects have <i>methods</i>, which are really just things you can ask them to do, like 'release pollen' or 'sting someone'. Finally, objects have <i>events</i>, or at least they can generate events. That could be 'I've been pollinated' or 'I left my stinger in someone'. Any particular object may make use of one, two or all three of these constructs.</div>
<div>
<br /></div>
<div>
Objects are based on <i>classes</i> in Java. There is an all too human tendency to use the terms interchangeably and I've probably been guilty of doing that, too. Technically, a class defines how an object should be built and an object is an <i>instance</i> of such a class. Basically, after you write your code you compile it to create a .class file, and then when you run your code you can make a new object from said class. Making objects is easy enough, most of them get created (or <i>instantiated</i>) by using the <i>new</i> keyword like this:<br />
<br />
SimpleObject myObject = new SimpleObject();<br />
<br />
Let's break that down:<br />
<br />
First, we have declared that we're interested in working with a variable of type SimpleObject. In other words, someone out there has written a <i>SimpleObject.java</i> file that defined a <i>SimpleObject</i> class and you're going to make an object from that definition.<br />
<br />
That variable will be called 'myObject'. We have to name our variables or we'd have a really hard time referring to them in our code!<br />
<br />
We're not referring to a previously existing <i>SimpleObject</i>, we're going to make a completely new one. The actual creation is handled by a <i>constructor</i> inside of <i>SimpleObject.java</i>, and we need to rely on that constructor doing its job, correctly setting up anything within the new object that needs to be in place. <br />
<br />
Some objects don't appear to have constructors at all if you read the code, but that just means that there is no need for a constructor to do any setup work, so the programmer was able to rely on Java creating a <i>default constructor</i> for them. The code for <i>SimpleObject</i> may have been written either way. We don't care at this point, we just know we can call it. I'll get back to constructors a little later when we talk about actually writing a class of your own.</div>
<div>
<br /></div>
<div>
Defining an class in Java is straightforward enough. You don't really have to do any more than create a .java file with a bit of correct syntax. The following example is enough to make a <i>SimpleObject</i> class (which really can't do anything but exist):<br />
<br />
<pre style="background-color: white; font-family: 'Courier New'; font-size: 9.6pt;"><span style="color: navy; font-weight: bold;">package </span>com.oopuniversity.simpleobject;
<span style="color: navy; font-weight: bold;">public class </span>SimpleObject {
}</pre>
</div>
<div>
<br />
Of course, a class that doesn't do anything isn't very useful, but I think it's good to have a picture in your head of all the 'extra' stuff that absolutely needs to be in place. Code can look a bit busy to new developers, and its best to know what is basically template stuff that you should make sure is there and then ignore.<br />
<br />
Just to break it down, that 'package' statement up at the top tells the compiler where the generated class file should go. It's basically specifying an output directory, but using periods instead of slashes or backslashes. Packaging is primarily an organizational tool and it turns out to be an important one later on.<br />
<br />
Then we have 'public class SimpleObject' which tells us we're defining a class called <i>SimpleObject</i>. That <i>public</i> keyword is important, it controls whether other objects in a larger program are able to create <i>SimpleObject</i>s or even refer to them at all. For now, just use 'public'. The day will come when you start to use other <i>modifiers</i> for specific reasons, but if you're reading this to learn you don't have those reasons yet.<br />
<br />
Then we have some curly braces. Those are ubiquitous in Java programs, and basically set boundaries for chunks of code. In this case, they are setting the boundary for the beginning and end of the class, although they don't actually contain anything. Anything between those brackets will be considered an attempt at having something be a part of <i>SimpleObject</i>.<br />
<br />
Man, four paragraphs to describe three lines... I guess a fair amount of information is consolidated down into even that useless bit of code! Fortunately, that stuff always stays pretty much the same. Once you understand that structure, you can kind of stop worrying about it and move on.<br />
<br />
I mentioned above that I would talk about constructors. Well, that time has come. The following code is (aside from being in a different package) precisely identical to the previous code:<br />
<br />
<pre style="background-color: white; font-family: 'Courier New'; font-size: 9.6pt;"><span style="color: navy; font-weight: bold;">package </span>com.oopuniversity.simpleobjectwithconstructor;
<span style="color: navy; font-weight: bold;">public class </span>SimpleObject {
<span style="color: navy; font-weight: bold;">public </span>SimpleObject() {
}
}</pre>
<pre style="background-color: white; font-family: 'Courier New'; font-size: 9.6pt;"></pre>
The only differences are:<br />
<br />
<ol>
<li>We changed the package definition, which lets us have this version of SimpleObject sit in the same project as the previous version without any conflicts.</li>
<li>Now we have something new inside the braces that define the class.</li>
</ol>
<br />
The package definition is needed because I'm keeping everything inside one big project. Just like you can't have two files with the same name in one directory, you can't have two classes with the same name in one package.<br />
<br />
The new stuff inside the braces is defining a <i>default constructor</i> for <i>SimpleObject</i>. It's <i>public</i> which means other objects can use it to make a <i>new SimpleObject</i>. It has nothing between the parentheses, which means you can create a <i>SimpleObject</i> without having to give it any <i>parameters</i>, which are nothing more than pieces of information you give it (we'll talk about those soon). Then it has some more of those fun curly braces, which again define boundaries. Anything inside this particular pair of braces belongs not just to the class, but to the constructor itself.<br />
<br />
Why would you want to write a constructor like this, making your class busier? Well, you wouldn't, and that's why you get this for free with any class you write that doesn't bother defining a constructor of its own. However, you DO need to know about and understand this for one simple reason: It is also possible to define a class using a constructor (or a whole bunch of them if you like) that has parameters. If you do this, the compiler will *not* create a default constructor for you and you won't be able to use a default constructor unless you explicitly write one.<br />
<br />
https://github.com/OOPUniversity/OOP_Basics</div>
J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.com0tag:blogger.com,1999:blog-8076032851736657838.post-63819292414042758872016-06-05T20:28:00.002-04:002016-06-08T05:25:34.487-04:00Put a Spring in your stepI don't know about you, but when it came time for me to figure out Spring's Java Annotation based configuration, I found it difficult to know what I really needed to do. Between well-meaning but outdated online tutorials, many different versions of the software each with its own quirks, and some guys who just plain got it wrong, I found the process far more confusing than it should be.<br />
<div>
<br /></div>
<div>
In fact, once I stripped a program down to its most basic elements (and I don't think there's much left to do here at all), it's kind of embarrassing to think I ever had a problem with it. In short, it's short. I found myself left with three classes, a few annotations, and a working program.<br />
<br />
Then just to gussy it up a bit, I created a complete alternate implementation of the entire package tree, which you can cause the program to use by specifying the package name as a command line parameter. You can create other implementations as well, link them in via separate jar files and run those, too, so long as the classes in question implement the interfaces in the 'resources' package.</div>
<div>
<br /></div>
<div>
Without further ado, here is the Spring Java Config Demo. I may update it with a few additional features in the days to come, but whatever I do add will be done in the most minimalist fashion possible.</div>
<div>
<br /></div>
<div>
<a href="https://github.com/OOPUniversity/SpringJavaConfigDemo">https://github.com/OOPUniversity/SpringJavaConfigDemo</a></div>
J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.com0tag:blogger.com,1999:blog-8076032851736657838.post-77871152655910975082016-06-05T07:36:00.004-04:002016-06-26T06:46:00.163-04:00JSON? What is this, Friday the 13th?JSON stands for "JavaScript Object Notation", and it is nothing more than a standardized format for pushing object properties around in text format. This is handy for many purposes, especially for transmitting objects over networks. I can create objects in Java, convert them to JSON, and then read them in Javascript on a browser. That's all kinds of handy.<br />
<br />
There are plenty of tools for working with JSON, I personally like Jackson from fasterxml.com. This package provides a great deal of functionality in an easy to use form. It's not the only JSON library out there, not by a long shot: But it's simple, quick, and widely used. It's also one of the core technologies selected for the 'DropWizard' framework, which I'll be talking about in another post.<br />
<br />
Have an object and want to make a JSON representation? Then ObjectMapper is the tool for you:<br />
<br />
First of all, let's create a simple object called 'Person'. For the sake of simplicity, we'll assume that all we care about is the name.<br />
<br />
<pre style="background-color: white; font-family: 'Courier New'; font-size: 9.6pt;"><span style="color: navy; font-weight: bold;">public class </span>Person {
<span style="color: navy; font-weight: bold;">private </span>String <span style="color: #660e7a; font-weight: bold;">givenName</span>;
<span style="color: navy; font-weight: bold;">private </span>String <span style="color: #660e7a; font-weight: bold;">surName</span>;
<span style="color: grey; font-style: italic;">// This object has to be a Bean, which means it needs a no-argument constructor</span><span style="color: grey; font-style: italic;"> </span></pre>
<pre style="background-color: white; font-family: 'Courier New'; font-size: 9.6pt;"><span style="color: navy; font-weight: bold;">
</span></pre>
<pre style="background-color: white; font-family: 'Courier New'; font-size: 9.6pt;"><span style="color: navy; font-weight: bold;"> public </span>Person() {}
<span style="color: navy; font-weight: bold;">public </span>Person(String surName, String givenName) {
<span style="color: navy; font-weight: bold;">this</span>.<span style="color: #660e7a; font-weight: bold;">surName </span>= surName;
<span style="color: navy; font-weight: bold;">this</span>.<span style="color: #660e7a; font-weight: bold;">givenName </span>= givenName;
}
<span style="color: navy; font-weight: bold;">public </span>String getGivenName() {
<span style="color: navy; font-weight: bold;">return </span><span style="color: #660e7a; font-weight: bold;">givenName</span>;
}
<span style="color: navy; font-weight: bold;">public void </span>setGivenName(String givenName) {
<span style="color: navy; font-weight: bold;">this</span>.<span style="color: #660e7a; font-weight: bold;">givenName </span>= givenName;
}
<span style="color: navy; font-weight: bold;">public </span>String getSurName() {
<span style="color: navy; font-weight: bold;">return </span><span style="color: #660e7a; font-weight: bold;">surName</span>;
}
<span style="color: navy; font-weight: bold;">public void </span>setSurName(String surName) {
<span style="color: navy; font-weight: bold;">this</span>.<span style="color: #660e7a; font-weight: bold;">surName </span>= surName;
}
<span style="color: olive;">@Override</span><span style="color: olive;"> </span><span style="color: navy; font-weight: bold;">public </span>String toString() {
<span style="color: navy; font-weight: bold;">return </span><span style="color: green; font-weight: bold;">"Person{" </span>+
<span style="color: green; font-weight: bold;">"givenName='" </span>+ <span style="color: #660e7a; font-weight: bold;">givenName </span>+ <span style="color: green; font-weight: bold;">'</span><span style="color: navy; font-weight: bold;">\'</span><span style="color: green; font-weight: bold;">' </span>+
<span style="color: green; font-weight: bold;">", surName='" </span>+ <span style="color: #660e7a; font-weight: bold;">surName </span>+ <span style="color: green; font-weight: bold;">'</span><span style="color: navy; font-weight: bold;">\'</span><span style="color: green; font-weight: bold;">' </span>+
<span style="color: green; font-weight: bold;">'}'</span>;
}
}</pre>
<br />
This import statement is important, and of course you'll have to get the .jar file to support it. I would suggest just using maven to deal with that.<br />
<br />
<pre style="background-color: white; font-size: 9.6pt;"><span style="font-family: "courier new" , "courier" , monospace;"><pre style="font-family: "Courier New"; font-size: 9.6pt;"><span style="color: navy; font-weight: bold;">import </span>com.fasterxml.jackson.databind.ObjectMapper;</pre>
<pre style="font-family: "Courier New"; font-size: 9.6pt;"></pre>
<pre style="font-family: "Courier New"; font-size: 9.6pt;">...</pre>
</span></pre>
<pre style="background-color: white; font-size: 9.6pt;"><span style="font-family: "courier new" , "courier" , monospace;"> ObjectMapper objectMapper = <span style="color: navy; font-weight: bold;">new </span>ObjectMapper();
</span></pre>
<pre style="background-color: white; font-size: 9.6pt;"><span style="font-family: "courier new" , "courier" , monospace;"> Person p = <span style="color: navy; font-weight: bold;">new </span>Person(<span style="color: green; font-weight: bold;">"Doe"</span>, <span style="color: green; font-weight: bold;">"John"</span>);
String jsonRepresentation = objectMapper.writeValueAsString(p);
System.<span style="color: #660e7a; font-style: italic; font-weight: bold;">out</span>.println(jsonRepresentation);</span><span style="font-family: "courier new";">
</span></pre>
<pre style="background-color: white; font-size: 9.6pt;"><span style="font-family: "courier new" , "courier" , monospace;">
</span></pre>
<pre style="background-color: white; font-size: 9.6pt;"><span style="font-family: "georgia" , "times new roman" , serif;">Going back the other way is even easier:</span></pre>
<pre style="background-color: white; font-size: 9.6pt;"><span style="font-family: "georgia" , "times new roman" , serif;">
</span></pre>
<pre style="background-color: white; font-size: 9.6pt;"><pre style="font-family: 'Courier New'; font-size: 9.6pt;">Person p2 = objectMapper.readValue(jsonRepresentation, Person.<span style="color: navy; font-weight: bold;">class</span>);</pre>
</pre>
<pre style="background-color: white;"><div style="font-family: 'times new roman'; font-size: medium; white-space: normal;">
This works very well within a single project of course. Let's say you need to persist your objects to disk for later use. Well, the JSON representation gives you an excellent way to do this without running into the various issues that straight Java object serialization can raise. Your files will be human-readable, human-editable, and they're much less likely to become unusable because you changed an object definition. What's not to love about that?<br />
In fact, reading and writing files is an extremely simple operation with Jackson. The ObjectMapper does most of the hard lifting for you and turns basic (or not so basic) persistence into one line operations. If you wanted to take that Person object up above and stash it in a file on your hard drive for later use all you'd need to do is this:<br />
<pre style="font-family: 'Courier New'; font-size: 9.6pt;"><span style="color: #660e7a; font-weight: bold;">objectMapper</span>.writeValue(<span style="color: navy; font-weight: bold;">new </span>File(<span style="color: green; font-weight: bold;">"JohnDoe.txt"</span>), p);</pre>
</div>
<div style="font-family: 'times new roman'; font-size: medium; white-space: normal;">
</div>
<pre style="background-color: white; font-size: 9.6pt;"><span style="font-family: "times new roman"; font-size: small; white-space: normal;">Reversing the operation is almost as easy: You just need to use one special little piece of syntax to tell ObjectMapper what kind of object you are creating:</span></pre>
<pre style="background-color: white; font-size: 9.6pt;"><span style="font-family: "times new roman"; font-size: small; white-space: normal;">
</span></pre>
<pre style="background-color: white; font-size: 9.6pt;"><pre style="font-family: 'Courier New'; font-size: 9.6pt;">Person p2 = <span style="color: #660e7a; font-weight: bold;">objectMapper</span>.readValue(<span style="color: navy; font-weight: bold;">new </span>File(<span style="color: green; font-weight: bold;">"JohnDoe.txt"</span>), Person.<span style="color: navy; font-weight: bold;">class</span>);</pre>
</pre>
<span style="font-size: 9.6pt;">
</span><div style="font-family: 'times new roman'; font-size: medium; white-space: normal;">
We've basically now recreated what we did in the first couple of examples, but we're able to run one example today and the next one tomorrow after restarting the computer if we want, since instead of just sitting in a String in our program's memory the important information is now sitting on your hard drive. The file looks like this, by the way:<br />
<pre style="font-family: 'Courier New'; font-size: 9.6pt;">{"givenName":"John","surName":"Doe"}</pre>
JSON is also great for transmitting data over networks. In fact, if you take a look at RESTful services (which I will visit in a future post) JSON is a standard way of communicating with them. You don't even have to care what language the remote system uses. Just so long as you both agree on the set of properties to be sent, the other end could be written in C, .NET, JavaScript (hey, look at what the 'J' stand for in the first place) or any other language. Maybe the other end is also written in Java, but it was developed by someone else who doesn't have access to your library with your definition of Person. That's perfectly OK, they can roll their own very easily and so long as the properties in your JSON are all supported everything will just work:<br />
Let's pretend we are on the other side now, and the file created above was sent to us. We want to bring the data into our system using our home grown "AnotherPerson" class. For demonstration purposes, the class is exactly the same as the "Person" class above, except for the property names. So it contains code like this:<br />
<pre style="font-family: 'Courier New'; font-size: 9.6pt;"><span style="color: navy; font-weight: bold;">public class </span>AnotherPersonNoAnnotations {
<span style="color: navy; font-weight: bold;">private </span>String <span style="color: #660e7a; font-weight: bold;">firstName</span>;
<span style="color: navy; font-weight: bold;">private </span>String <span style="color: #660e7a; font-weight: bold;">lastName</span>;
<span style="color: grey; font-style: italic;">// This object has to be a Bean, which means it needs a no-argument constructor</span><span style="color: grey; font-style: italic;"> </span></pre>
<pre style="font-family: 'Courier New'; font-size: 9.6pt;"><span style="color: navy; font-weight: bold;">
</span></pre>
<pre style="font-family: 'Courier New'; font-size: 9.6pt;"><span style="color: navy; font-weight: bold;">public </span>AnotherPersonNoAnnotations() {}
<span style="color: navy; font-weight: bold;">public </span>AnotherPersonNoAnnotations(String lastName, String firstName) {
<span style="color: navy; font-weight: bold;">this</span>.<span style="color: #660e7a; font-weight: bold;">lastName </span>= lastName;
<span style="color: navy; font-weight: bold;">this</span>.<span style="color: #660e7a; font-weight: bold;">firstName </span>= firstName;
}
<span style="color: navy; font-weight: bold;">public </span>String getFirstName() {
<span style="color: navy; font-weight: bold;">return </span><span style="color: #660e7a; font-weight: bold;">firstName</span>;
}
<span style="color: navy; font-weight: bold;">public void </span>setFirstName(String firstName) {
<span style="color: navy; font-weight: bold;">this</span>.<span style="color: #660e7a; font-weight: bold;">firstName </span>= firstName;
}</pre>
<pre style="font-family: 'Courier New'; font-size: 9.6pt;"> ...</pre>
<pre style="font-family: 'Courier New'; font-size: 9.6pt;"></pre>
When we try to read the object, we do this:<br />
<pre style="font-family: 'Courier New'; font-size: 9.6pt;">AnotherPerson p = <span style="color: #660e7a; font-weight: bold;">objectMapper</span>.readValue(<span style="color: navy; font-weight: bold;">new </span>File(<span style="color: green; font-weight: bold;">"JohnDoe.txt"</span>), AnotherPerson.<span style="color: navy; font-weight: bold;">class</span>);</pre>
</div>
<span style="font-size: 9.6pt;">
</span><div style="font-family: 'times new roman'; font-size: medium; white-space: normal;">
</div>
<span style="font-size: 9.6pt;">
</span><div style="font-family: 'Times New Roman'; font-size: medium; white-space: normal;">
<div style="font-family: 'times new roman'; font-size: medium; white-space: normal;">
And it fails spectacularly!</div>
<div style="font-family: 'times new roman'; font-size: medium; white-space: normal;">
</div>
<div style="font-family: 'times new roman'; font-size: medium; white-space: normal;">
</div>
<span style="font-family: "times new roman";"><span style="white-space: normal;"><b>Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "givenName" (class com.oopuniversity.json.model.AnotherPersonNoAnnotations), not marked as ignorable (2 known properties: "lastName", "firstName"])</b></span></span><br />
<span style="font-family: "times new roman";"><span style="white-space: normal;"><b> at [Source: {"givenName":"John","surName":"Doe"}; line: 1, column: 15] (through reference chain: com.oopuniversity.json.model.AnotherPersonNoAnnotations["givenName"])</b></span></span><br />
<span style="font-family: "times new roman";"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:62)</b></span><br />
<span style="font-family: "times new roman";"><b> ...</b></span><br />
<div style="font-family: 'times new roman'; font-size: medium; white-space: normal;">
</div>
<div style="font-family: 'times new roman'; font-size: medium; white-space: normal;">
</div>
<div style="font-family: 'times new roman'; font-size: medium; white-space: normal;">
The actual error will be followed by a whole bunch more stuff, but the important information is right at the top. And notice: This is an extremely useful error message. It tells you exactly what went wrong and why. It's an "UnrecognizedPropertyException" which means exactly what it says: Jackson did not recognize a property it found. Then it flat out tells you that 'givenName' is the problem. It also tells you which properties it <i>can</i> recognize. Then to top it off it shows you the exact JSON it was trying to read. I wish all libraries were this good at telling us what went wrong.</div>
<div style="font-family: 'times new roman'; font-size: medium; white-space: normal;">
</div>
<div style="font-family: 'times new roman'; font-size: medium; white-space: normal;">
So now we know that our object supports "lastName" and "firstName" but the data contains "givenName" and "surName". Fixing this is quite simple.</div>
<div style="font-family: 'times new roman'; white-space: normal;">
</div>
<div style="font-family: 'times new roman'; white-space: normal;">
Not to worry, even though we have different names for our properties we'll be fine. This is far from an uncommon situation and Jackson has it handled. All we need to do is add a couple of 'annotations' to our code. Annotations are a clever addition that was made to Java years ago. Classes, properties and methods can be annotated in order to add new behaviors. In this case, we'll use them to inform Jackson that we are expecting different field names. We change our 'AnotherPerson' class so that the declarations look like this:</div>
<div style="font-family: 'times new roman'; white-space: normal;">
</div>
<pre style="font-family: 'Courier New'; font-size: 9.6pt;"><span style="color: navy; font-weight: bold;">public class </span>AnotherPerson {
<span style="color: olive;">@JsonProperty</span>(<span style="color: green; font-weight: bold;">"givenName"</span>)
<span style="color: navy; font-weight: bold;">private </span>String <span style="color: #660e7a; font-weight: bold;">firstName</span>;
<span style="color: olive;">@JsonProperty</span>(<span style="color: green; font-weight: bold;">"surName"</span>)
<span style="color: navy; font-weight: bold;">private </span>String <span style="color: #660e7a; font-weight: bold;">lastName</span>;</pre>
<div style="font-family: 'times new roman'; white-space: normal;">
</div>
<div style="font-family: 'times new roman'; white-space: normal;">
I think that's pretty self-explanatory. We're telling Jackson that when it's processing our file, it should think of our 'firstName' field as though it was called 'givenName', and of course the same thing applies to 'lastName' and 'surName'. These annotations affect both reading and writing and now our class, while it uses our preferred variable names internally, looks to the outside world exactly like the Person class listed above.</div>
<div style="font-family: 'times new roman'; white-space: normal;">
</div>
<div style="font-family: 'times new roman'; white-space: normal;">
Now our attempt to read the file works beautifully:</div>
<div style="font-family: 'times new roman'; white-space: normal;">
</div>
<span style="white-space: normal;"><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">AnotherPerson{firstName='John', lastName='Doe'}</span></span><br />
<div>
<span style="font-size: x-small;">
</span></div>
<div style="font-family: 'times new roman'; white-space: normal;">
</div>
<div style="font-family: 'times new roman'; font-size: medium; white-space: normal;">
This is not all there is to say about JSON processing with Jackson, but it is certainly a good start. I'm sure I'll be talking about it more in posts to come. I mentioned but did not talk about using this stuff to communicate between running systems (via RESTful services) and that's a key area that many developers will want to understand.</div>
<div style="font-family: 'times new roman'; font-size: medium; white-space: normal;">
</div>
<div style="font-family: 'times new roman'; font-size: medium; white-space: normal;">
A code repository with working examples can be found here.</div>
</div>
<span style="font-size: 9.6pt;">
</span><div style="font-size: 9.6pt;">
</div>
<span style="font-size: 9.6pt;">
</span></pre>
<pre style="background-color: white;"><span style="font-size: 12.8px;">https://github.com/OOPUniversity/JSON_Basics</span></pre>
J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.com0tag:blogger.com,1999:blog-8076032851736657838.post-69157608307042864212016-06-03T20:36:00.000-04:002016-06-05T08:32:05.892-04:00Super basic object stuff<form action="https://www.reddit.com/r/javahelp/comments/4mcadr/beginner_how_do_i_properly_load_ints_from_an/#" class="usertext warn-on-unload" id="form-t1_d3ub728oci" style="background-color: white; font-family: verdana, arial, helvetica, sans-serif; font-size: small; margin: 0px; padding: 0px;">
<div class="usertext-body may-blank-within md-container " style="margin: 0px; padding: 0px;">
<div class="md" style="color: #222222; font-size: 1.07692em; margin: 5px 0px; max-width: 60em; overflow-wrap: break-word; padding: 0px; word-wrap: break-word;">
<div style="font-size: 1em; line-height: 1.42857em; margin-bottom: 0.357143em; padding: 0px;">
<span style="font-size: 1em; line-height: 1.42857em;">I am not going to rework this right now, I think it gets the main points across as is.</span></div>
<div style="font-size: 1em; line-height: 1.42857em; margin-bottom: 0.357143em; padding: 0px;">
<br /></div>
<div style="font-size: 1em; line-height: 1.42857em; margin-bottom: 0.357143em; padding: 0px;">
<span style="font-size: 14px; line-height: 19.9999px;">From a recent Reddit post:</span></div>
<div style="font-size: 1em; line-height: 1.42857em; margin-bottom: 0.357143em; padding: 0px;">
<br /></div>
<div style="font-size: 1em; line-height: 1.42857em; margin-bottom: 0.357143em; padding: 0px;">
What you are asking about is quite basic to object oriented programming. Let's start with the first point I'd like to make: PersonA and PersonB are exactly the same thing, except the data is different. However, they cannot be simple methods that return integer values, that will never fly. The values you're setting up are lost as soon as the methods end.</div>
<div style="font-size: 1em; line-height: 1.42857em; margin-bottom: 0.357143em; margin-top: 0.357143em; padding: 0px;">
Instead, you want to create <em style="font-weight: inherit; margin-left: 0px; margin-right: 0px; margin-top: 0px;">objects</em> of type <em style="font-weight: inherit; margin-bottom: 0px; margin-left: 0px; margin-right: 0px;">Person</em>. You do this by creating a class called Person and setting up variables to represent the values you want. At its absolute most basic (and this isn't correct, it's just showing the idea) it would look like this:</div>
<pre style="background: url("//b.thumbs.redditmedia.com/VXmIcG8Y6N1hYTnm.png") 0% 0% repeat; border-radius: 2px; border: 1px solid rgb(0, 0, 0); font-family: 'Courier New', courier, monospace; line-height: 15px; margin-bottom: 0.357143em; margin-top: 25px; overflow: auto; padding: 4px 9px; position: relative; z-index: 1;"><code style="background-color: transparent; border-radius: 2px; border: 0px; display: block; font-family: 'Courier New', courier, monospace; font-size: 1em; margin: 0px 2px 0px 35px; overflow: auto; padding: 11px !important; word-break: normal;">public class Person {
public int x;
public int y;
public int range;
}
</code></pre>
<div style="font-size: 1em; line-height: 1.42857em; margin-bottom: 0.357143em; margin-top: 0.357143em; padding: 0px;">
This is more akin to what we used to call a <em style="font-weight: inherit; margin: 0px;">struct</em> in c. Ordinarily you'd have a lot more stuff in there, but adding that right now could inhibit understanding so I want to take this slowly.</div>
<div style="font-size: 1em; line-height: 1.42857em; margin-bottom: 0.357143em; margin-top: 0.357143em; padding: 0px;">
With the above class you could do this in the class you've posted:</div>
<pre style="background: url("//b.thumbs.redditmedia.com/VXmIcG8Y6N1hYTnm.png") 0% 0% repeat; border-radius: 2px; border: 1px solid rgb(0, 0, 0); font-family: 'Courier New', courier, monospace; line-height: 15px; margin-bottom: 0.357143em; margin-top: 25px; overflow: auto; padding: 4px 9px; position: relative; z-index: 1;"><code style="background-color: transparent; border-radius: 2px; border: 0px; display: block; font-family: 'Courier New', courier, monospace; font-size: 1em; margin: 0px 2px 0px 35px; overflow: auto; padding: 11px !important; word-break: normal;">public static void main(String [] args) {
Person a = new Person();
a.x = 200;
a.y = 100;
a.range = 160;
Person b = new Person();
b.x = 100;
b.y = 400;
b.range = 170;
</code></pre>
<div style="font-size: 1em; line-height: 1.42857em; margin-bottom: 0.357143em; margin-top: 0.357143em; padding: 0px;">
After that, you could use 'a.x' or 'b.range' the same way you were originally trying to use 'xA' or 'rangeB'.</div>
<div style="font-size: 1em; line-height: 1.42857em; margin-bottom: 0.357143em; margin-top: 0.357143em; padding: 0px;">
Remember when I said that I was just showing the basics? Well, objects are a lot more powerful than just bags of variables. Let's use just another couple of features.</div>
<div style="font-size: 1em; line-height: 1.42857em; margin-bottom: 0.357143em; margin-top: 0.357143em; padding: 0px;">
First, let's make a 'constructor' for Person so you can slim down your code:</div>
<pre style="background: url("//b.thumbs.redditmedia.com/VXmIcG8Y6N1hYTnm.png") 0% 0% repeat; border-radius: 2px; border: 1px solid rgb(0, 0, 0); font-family: 'Courier New', courier, monospace; line-height: 15px; margin-bottom: 0.357143em; margin-top: 25px; overflow: auto; padding: 4px 9px; position: relative; z-index: 1;"><code style="background-color: transparent; border-radius: 2px; border: 0px; display: block; font-family: 'Courier New', courier, monospace; font-size: 1em; margin: 0px 2px 0px 35px; overflow: auto; padding: 11px !important; word-break: normal;">public class Person {
... //What you already have
public Person(int newX, int newY, int newRange) {
x = newX;
y = newY;
range = newRange;
}
}
</code></pre>
<div style="font-size: 1em; line-height: 1.42857em; margin-bottom: 0.357143em; margin-top: 0.357143em; padding: 0px;">
Now your main can do this:</div>
<pre style="background: url("//b.thumbs.redditmedia.com/VXmIcG8Y6N1hYTnm.png") 0% 0% repeat; border-radius: 2px; border: 1px solid rgb(0, 0, 0); font-family: 'Courier New', courier, monospace; line-height: 15px; margin-bottom: 0.357143em; margin-top: 25px; overflow: auto; padding: 4px 9px; position: relative; z-index: 1;"><code style="background-color: transparent; border-radius: 2px; border: 0px; display: block; font-family: 'Courier New', courier, monospace; font-size: 1em; margin: 0px 2px 0px 35px; overflow: auto; padding: 11px !important; word-break: normal;">Person a = new Person(200, 100, 160);
</code></pre>
<div style="font-size: 1em; line-height: 1.42857em; margin-bottom: 0.357143em; margin-top: 0.357143em; padding: 0px;">
Isn't that nicer?</div>
<div style="font-size: 1em; line-height: 1.42857em; margin-bottom: 0.357143em; margin-top: 0.357143em; padding: 0px;">
Next, let's add 'accessor' methods to Person. Accessors are also called 'getters' and there are good reasons to use them. Trust me on this, I'm on the train and don't have time to fully explain:</div>
<pre style="background: url("//b.thumbs.redditmedia.com/VXmIcG8Y6N1hYTnm.png") 0% 0% repeat; border-radius: 2px; border: 1px solid rgb(0, 0, 0); font-family: 'Courier New', courier, monospace; line-height: 15px; margin-bottom: 0.357143em; margin-top: 25px; overflow: auto; padding: 4px 9px; position: relative; z-index: 1;"><code style="background-color: transparent; border-radius: 2px; border: 0px; display: block; font-family: 'Courier New', courier, monospace; font-size: 1em; margin: 0px 2px 0px 35px; overflow: auto; padding: 11px !important; word-break: normal;">public class Person {
... //What you already have
public int getX() {
return x;
}
//Do the same thing for 'y' and 'range'
}
</code></pre>
<div style="font-size: 1em; line-height: 1.42857em; margin-bottom: 0.357143em; margin-top: 0.357143em; padding: 0px;">
At this point, you could still do 'a.x = 5' or 'range = b.range'. We can prevent that by marking the variables as 'private'</div>
<pre style="background: url("//b.thumbs.redditmedia.com/VXmIcG8Y6N1hYTnm.png") 0% 0% repeat; border-radius: 2px; border: 1px solid rgb(0, 0, 0); font-family: 'Courier New', courier, monospace; line-height: 15px; margin-bottom: 0.357143em; margin-top: 25px; overflow: auto; padding: 4px 9px; position: relative; z-index: 1;"><code style="background-color: transparent; border-radius: 2px; border: 0px; display: block; font-family: 'Courier New', courier, monospace; font-size: 1em; margin: 0px 2px 0px 35px; overflow: auto; padding: 11px !important; word-break: normal;">public class Person {
private int x;
private int y;
private int range;
... //what you otherwise already have
}
</code></pre>
<div style="font-size: 1em; line-height: 1.42857em; margin-bottom: 0.357143em; margin-top: 0.357143em; padding: 0px;">
But wait! Now when I try to write a.x=5 I get some horrible error and everything is broken and the world is ending!</div>
<div style="font-size: 1em; line-height: 1.42857em; margin-bottom: 0.357143em; margin-top: 0.357143em; padding: 0px;">
No, you just need 'setters', also known as modifiers to do the job for you:</div>
<pre style="background: url("//b.thumbs.redditmedia.com/VXmIcG8Y6N1hYTnm.png") 0% 0% repeat; border-radius: 2px; border: 1px solid rgb(0, 0, 0); font-family: 'Courier New', courier, monospace; line-height: 15px; margin-bottom: 0.357143em; margin-top: 25px; overflow: auto; padding: 4px 9px; position: relative; z-index: 1;"><code style="background-color: transparent; border-radius: 2px; border: 0px; display: block; font-family: 'Courier New', courier, monospace; font-size: 1em; margin: 0px 2px 0px 35px; overflow: auto; padding: 11px !important; word-break: normal;">public class Person {
... //Everything you already have
public void setX(int newX) {
x = newX;
}
// Follow the same pattern for y and range
}
</code></pre>
<div style="font-size: 1em; line-height: 1.42857em; margin-bottom: 0.357143em; margin-top: 0.357143em; padding: 0px;">
Now the equivalent to 'int range = a.range' is 'int range = a.getRange()', and the equivalent of 'a.range = 50' is 'a.setRange(50)'.</div>
<div style="font-size: 1em; line-height: 1.42857em; margin-bottom: 0.357143em; margin-top: 0.357143em; padding: 0px;">
There's a LOT more to OOP, we've really just scratched the surface. But just encapsulating your data in this way will go a long way towards making your programs more readable, maintainable and robust.</div>
<div style="font-size: 1em; line-height: 1.42857em; margin-top: 0.357143em; padding: 0px;">
I have no doubt that questions are coming up in your mind. I tried to make this clear and left out a few niceties in the interest of getting it written quickly and not overloading you, but it's a lot to absorb. Please ask questions when you need clarification.</div>
<div>
<br /></div>
</div>
</div>
</form>
J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.com0tag:blogger.com,1999:blog-8076032851736657838.post-24936340458176438942015-11-15T10:58:00.001-05:002015-11-15T10:59:59.346-05:00There's a loop for each of usThis is one of the really useful additions to the Java language specifications. It greatly simplifies many loop structures, eliminating a bunch of verbiage that we long thought was just part of the deal when writing code.<br />
<br />
Let's meet what I hope will become a good friend of yours: The enhanced for, also known as the 'for each' loop.<br />
<br />
The for each loop structure is an enhancement that can be used to replace many of the standard for or while loops you would otherwise be writing. It is extremely common to have to, for instance, go over the elements of an array or a collection, extract one element at a time, and perform operations on it. Let's pretend that we have an ArrayList of Person objects, and we want to print a list of first and last names.<br />
<br />
In the old days we might have written this (and if you don't understand why I use 'List' instead of 'ArrayList' see '<a href="http://www.oopuniversity.com/2014/12/good-practices-coding-to-interface.html">Good Practices: Coding to the Interface</a>'):<br />
<br />
<pre style="background-color: white; font-family: 'Courier New'; font-size: 12pt;"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span style="color: navy; font-weight: bold;">public static void </span>printPersonList1(List personList) {
System.<span style="color: #660e7a; font-style: italic; font-weight: bold;">out</span>.println(<span style="color: green; font-weight: bold;">"Using a 'while' loop the JDK 1.4 (and earlier) way:"</span>);
Iterator iter = personList.iterator();
<span style="color: navy; font-weight: bold;">while</span>(iter.hasNext()) {
Person p = (Person) iter.next();
System.<span style="color: #660e7a; font-style: italic; font-weight: bold;">out</span>.println(p.getFirstName() + <span style="color: green; font-weight: bold;">" " </span>+ p.getLastName());
}
}</span></pre>
<br />
Now, one improvement was the addition of 'Generics', which allowed us to simplify the code a bit by informing the compiler that our List and Iterator had to be of type Person:<br />
<br />
<pre style="background-color: white; font-family: 'Courier New'; font-size: 12pt;"><span style="font-size: x-small;"><span style="color: navy; font-weight: bold;">public static void </span>printPersonList2(List personList) {
System.out.println(<span style="color: green; font-weight: bold;">"Using a 'while' loop with generics:"</span>);
Iterator <Person> iter = personList.iterator();
<span style="color: navy; font-weight: bold;">while</span>(iter.hasNext()) {
Person p = iter.next();
System.<span style="color: #660e7a; font-style: italic; font-weight: bold;">out</span>.println(p.getFirstName() + <span style="color: green; font-weight: bold;">" " </span>+ p.getLastName());
}
}</span></pre>
<br />
Now, you might be wondering why I did my demonstrations of old style code with while loops to demonstrate a better for loop. This is mostly because the while loop syntax is better suited to running over an <i>Iterator</i> than an old style for loop was. It could be done, but frankly it's not as clean. You'll note I had to leave out the third term of the for loop because it only gets executed after the body of the loop is complete and I had to pre-seed with the first value:<br />
<br />
<pre style="background-color: white; font-family: 'Courier New'; font-size: 12pt;"><span style="font-size: x-small;"><span style="color: navy; font-weight: bold;">public static void </span>printPersonList3(List<Person> personList) {
System.<span style="color: #660e7a; font-style: italic; font-weight: bold;">out</span>.println(<span style="color: green; font-weight: bold;">"Using a 'for' loop with generics:"</span>);
Person p = <span style="color: navy; font-weight: bold;">null</span>;
<span style="color: navy; font-weight: bold;">for</span>(Iterator <Person> iter = personList.iterator(); iter.hasNext(); ) {
p = iter.next();
System.<span style="color: #660e7a; font-style: italic; font-weight: bold;">out</span>.println(p.getFirstName() + <span style="color: green; font-weight: bold;">" " </span>+ p.getLastName());
}
}</span></pre>
<pre style="background-color: white; font-family: 'Courier New'; font-size: 12pt;"></pre>
<br />
Alternately, we could have skipped the Iterator altogether, which is really more in keeping with the natural usage of the old style for loop:<br />
<br />
<pre style="background-color: white; font-family: 'Courier New'; font-size: 12pt;"><span style="font-size: x-small;"><span style="color: navy; font-weight: bold;">public static void </span>printPersonList4(List<Person> personList) {
System.<span style="color: #660e7a; font-style: italic; font-weight: bold;">out</span>.println(<span style="color: green; font-weight: bold;">"Using a 'for' loop with no iterator:"</span>);
Person p = <span style="color: navy; font-weight: bold;">null</span>;
<span style="color: navy; font-weight: bold;">for</span>(<span style="color: navy; font-weight: bold;">int </span>i = <span style="color: blue;">0</span>; i < personList.size(); i++) {
p = personList.get(i);
System.<span style="color: #660e7a; font-style: italic; font-weight: bold;">out</span>.println(p.getFirstName() + <span style="color: green; font-weight: bold;">" " </span>+ p.getLastName());
}
}</span></pre>
<pre style="background-color: white; font-family: 'Courier New'; font-size: 12pt;"></pre>
<br />
OK, here's the actual example I'm trying to get across to you. This is the 'enhanced for' loop, also knows as the 'for each':<br />
<br />
But the for each loop construct went a lot further and made things much better:<br />
<br />
<pre style="background-color: white; font-family: 'Courier New'; font-size: 12pt;"><span style="font-size: x-small;"><span style="color: navy; font-weight: bold;">public static void </span>printPersonList5(List<Person> personList) {
System.<span style="color: #660e7a; font-style: italic; font-weight: bold;">out</span>.println(<span style="color: green; font-weight: bold;">"Using a 'for each' loop:"</span>);
<span style="color: navy; font-weight: bold;">for</span>(Person p:personList) {
System.<span style="color: #660e7a; font-style: italic; font-weight: bold;">out</span>.println(p.getFirstName() + <span style="color: green; font-weight: bold;">" " </span>+ p.getLastName());
}
}</span></pre>
<div>
<br /></div>
Note how concise it is, with no extra stuff. Get Person objects from this collection and run with it. Using the enhanced for loop simplifies our code, letting us get on with the conceptual task at hand and saving our fingers from some typing. It's extremely common to go over a collection of data and perform some task on every element, so why should we have to write it all out explicitly every time? You can use for each loops on classes based on Collection and on arrays equally well, which means we're more likely to use it and get the code right the first time.<br />
<br />
<pre style="background-color: white; font-family: 'Courier New'; font-size: 12pt;"><span style="font-size: x-small;"><span style="color: navy; font-weight: bold;">private static void </span>printStringArray(String[] aList) {
System.<span style="color: #660e7a; font-style: italic; font-weight: bold;">out</span>.println(<span style="color: green; font-weight: bold;">"The enhanced for can also work on array types:"</span>);
<span style="color: navy; font-weight: bold;">for</span>(String s: aList) {
System.<span style="color: #660e7a; font-style: italic; font-weight: bold;">out</span>.println(s);
}
System.<span style="color: #660e7a; font-style: italic; font-weight: bold;">out</span>.println();
}</span></pre>
<br />
It actually took me a while to get used to using this loop structure, because I spent so much time supporting code that had to run in 1.4 level JREs. In order to ensure the best compatibility I was also compiling with a 1.4 JDK so I didn't have access to this feature. I'll tell you what, I was really missing out. My fingers are probably a couple of millimeters shorter than they should be because of all the wear and tear from the extra typing I did. I for one am glad we have this loop available, and you probably should be, too.<br />
<br />
<a href="https://gist.github.com/OOPUniversity/6b810399bd8f8e8b255c">View Code</a><br />
<br />
<br />J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.com0tag:blogger.com,1999:blog-8076032851736657838.post-14282173168284065972015-11-13T18:28:00.001-05:002015-11-13T18:28:18.852-05:00Paris :-(My heart goes out to the residents and visitors of the City of Light this evening.J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.com0tag:blogger.com,1999:blog-8076032851736657838.post-35278890689771079452015-11-13T16:01:00.004-05:002015-11-13T16:01:47.314-05:00Design Patterns: SingletonThe word 'singleton' is used to describe a design pattern for objects where only one instance of the object is allowed to exist.<br />
<br />
It would technically be possible for you to use nearly any Java class as a singleton by being very, very careful to only create one instance and use it throughout your application. But why do you want to work that hard? It's pretty easy to force a class to act as a singleton with a few lines of code.<br />
<br />
First of all, we make sure that there is no constructor available to the public. This means we must create at least one constructor and mark it with the keyword <i>private</i>. This will keep random objects from just creating their own instances of the class you wish to protect.<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> public class MySingletonClass {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> private MySingletonClass() {}</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> }</span><br />
<br />
Of course, that means you can't create your single object either! Never fear, we can get around that. After all, the singleton class itself can still invoke the constructor. Since we can't make an instance, though, it will have to be a static method. I prefer to call it 'getInstance' because that's a good description of what it does.<br />
<br />
Of course, it's not safe or desirable to have getInstance just create a new object each time it's called. So instead we'll store an object reference of the classes' own type inside it and use that:<br />
<br />
<span style="color: #cccccc; font-family: Courier New, Courier, monospace; font-size: x-small;"> public class MySingletonClass {</span><br />
<span style="color: #cccccc; font-family: Courier New, Courier, monospace; font-size: x-small;"> private MySingletonClass() {}</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> private static MySingletonClass singleton = null;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> ....</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> public static MySingletonClass getInstance() {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> ....</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> return singleton;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> <span style="color: #cccccc;"> }</span></span><br />
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span></div>
And the rest is just the work that needs to be done to make this function reliably:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> </span><span style="color: #cccccc; font-family: 'Courier New', Courier, monospace; font-size: x-small;"> public class MySingletonClass {</span><br />
<span style="color: #cccccc; font-family: Courier New, Courier, monospace; font-size: x-small;"> private MySingletonClass() {}</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="color: #cccccc;"> private static MySingletonClass singleton = null;</span></span><br />
<span style="color: #cccccc; font-family: Courier New, Courier, monospace; font-size: x-small;"> ....</span><br />
<span style="color: #cccccc;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> </span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> public static MySingletonClass getInstance() {</span></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> if (null == singleton) {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> singleton = new MySingletonClass();</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> <span style="color: #cccccc;"> return singleton; </span></span><br />
<span style="color: #cccccc; font-family: Courier New, Courier, monospace; font-size: x-small;"> }</span><br />
<span style="color: #cccccc; font-family: Courier New, Courier, monospace; font-size: x-small;"> }</span><br />
<div>
<br /></div>
<div>
So what have we done here? We've created a class that can't just be instantiated by anyone. Instead, we've enforced a contract on client classes, one that states they can only create one copy of this object. Whichever object attempts to obtain the singleton first will (unknowingly) be responsible for creating it as well in a case of <i>lazy initialization</i>. The <i>getInstance</i> method is our gatekeeper for this, handing out the same object reference whenever asked:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> MySingletonClass aSingleton = MySingletonClass.getInstance();</span></div>
<div>
<br /></div>
<div>
As you can see, using it is pretty easy. You could of course provide parameters to this method and pass them on to the constructor if needed.</div>
J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.com0tag:blogger.com,1999:blog-8076032851736657838.post-13974056582020930992015-11-11T10:09:00.007-05:002015-11-11T10:22:41.680-05:00Stop giving me so much staticLet's talk about the keyword <i>static</i> for a moment.<br />
<br />
There are two different uses for this in our code. It can be applied to methods or it can be applied to variables.<br />
<br />
When static is applied, it disassociates the item being declared from any specific instance of the class. For methods, this means that the method can be called by anyone at any time without creating a new class of that type. This can be particularly handy for utility functions, initializers, or any other chunk of code that wants to run without caring that it's about a particular person, bill, or list of stocks. For variables, it mostly means that the value is shared across all instances of the class.<br />
<h4>
Static Methods</h4>
<div>
Static methods can be called without making a new class. For instance, it could be used for a <i>factory method</i>, which is a design pattern that calls for objects to be built by calling a function to do so.</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">public class Person {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ...</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> public static Person createPerson(firstName, lastName) {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ...</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">}</span></div>
<div>
<br /></div>
<div>
You can call <i>createPerson</i> without having a Person object, like so:</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">Person.createPerson("John", "Doe");</span></div>
<div>
<br /></div>
<div>
Many utility functions are declared as static, and as a general rule they will need to operate free of any context supplied by objects.</div>
<h4>
Static Variables</h4>
<div>
Static variables come from the same basic idea of being disassociated from any specific instances of the class. They're useful for maintaining overall context, for instance, if we want to keep track of how many Person objects we've created we could write something like this:</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">public class Person {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ...</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> private static int numberCreated = 0;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ...</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> public static Person createPerson(firstName, lastName) {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ...</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> numberCreated ++;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ...</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">}</span></div>
</div>
<div>
<br /></div>
<div>
Now, every time we invoke <i>createPerson</i>, we'll also be incrementing the value of <i>numberCreated</i>, and it will always be available as a statistic our programs can check.</div>
<div>
<br /></div>
<div>
Many times, inexperienced programmers will overuse static methods, because when they first start creating methods and functions, they just call them from <i>main</i>. Your <i>main</i> method has to be static, and if you try calling non-static methods directly from it, the compiler complains. So the path of least resistance is often seen as just making those other methods static too. This does seem to work, but it goes against object oriented design principals, and it's best to nip this in the bud. So they start with this:</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">public class OutputTest {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ...</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> private PrintStream outputStream = ...;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ...</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> public static void main(String [] args) {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> print("This is a test");</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ...</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> public void print(String message) {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> outputStream.println(message);</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">}</span></div>
</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
But that fails because you can't call 'print' from a static context, so they change it to this</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">public class OutputTest {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ...</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> private PrintStream outputStream = ...;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ...</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> public static void main(String [] args) {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> print("This is a test");</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ...</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> public static void print(String message) {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> outputStream.println(message);</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">}</span></div>
</div>
<div>
<br /></div>
<div>
<div>
That fails, too, because outputStream isn't static, so they change the code again:</div>
<div>
<br /></div>
<div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">public class OutputTest {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ...</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> private static PrintStream outputStream = ...;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ...</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> public static void main(String [] args) {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> print("This is a test");</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ...</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> public static void print(String message) {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> outputStream.println(message);</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">}</span></div>
</div>
</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
And they're satisfied. Everything works now! I call this the <i>static cascade</i>, and I recommend avoiding it. If you did not originally intend for these items to be shared and free of binding to specific objects, then don't go changing them to act that way. </div>
<div>
<div>
</div>
</div>
</div>
<div>
<div>
<br /></div>
<div>
Get used to writing object oriented code. Do this instead:</div>
<div>
<br /></div>
<div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">public class OutputTest {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ...</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> private PrintStream outputStream = ...;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ...</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> public static void main(String [] args) {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> OutputTest test = new OutputTest(); //The key!</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> test.print("This is a test");</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> ...</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> public void print(String message) {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> outputStream.println(message);</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">}</span></div>
</div>
</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
While it might be a bit more of a conceptual leap, it's actually a far smaller change to the original code, and it opens your class up to being more adaptable to use in other systems. It's also a necessary step towards object oriented thinking, so you might as well get it over with now.</div>
<div>
<div>
</div>
</div>
</div>
J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.com0tag:blogger.com,1999:blog-8076032851736657838.post-71636168781031637102015-11-11T07:33:00.003-05:002015-11-11T07:33:37.859-05:00It's the final countdown!Many times we declare a variable that we really ought not to change, at least in some particular spot. We can just remember not to change it, and that might work. A better solution is to let the language keep us from even trying, and Java offers us the <i>final</i> keyword for this purpose.<br />
<br />
A variable declared as final cannot be changed, so maybe the word 'variable' does not even really apply, so we can call them 'constants' if we like. This has a couple of different purposes. First off, we might want to set up a constant like an approximation of pi for use in a class that does geometric calculations:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">static final float pi = 3.14159;</span><br />
<br />
Now any code that tries to change pi will be flagged by the compiler as a problem.<br />
<br />
Another use for the <i>final</i> keyword is to make sure that methods don't modify parameters we've given them:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">public void calculateValue (final int quantity) {</span><br />
<br />
This would make sure that we don't accidentally change quantity somewhere inside the calculateValue method.<br />
<br />
The compiler is able to simplify the code that it generates for variables declared as 'final', so we get that benefit, too. In short, it's a good idea to declare things as final whenever it's reasonably possible to do so.J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.com1tag:blogger.com,1999:blog-8076032851736657838.post-48223229404301353092015-11-10T11:29:00.002-05:002016-12-09T12:41:09.570-05:00I tried to print my array but all I got was gobbledegook!This is inspired by a post at /r/javahelp.<br />
<br />
A user posted that they were trying to print a sorted array to the console with System.out,println, and that instead of anything that made sense they got <span style="background-color: #fafafa; color: #222222; font-family: "verdana" , "arial" , "helvetica" , sans-serif; font-size: 14px; line-height: 20px;">[</span><a href="mailto:I@4969dd64" rel="nofollow" style="background-color: #fafafa; color: #0079d3; font-family: verdana, arial, helvetica, sans-serif; font-size: 14px; line-height: 20px; margin: 0px; text-decoration: none;">I@4969dd64</a><span style="background-color: #fafafa; color: #222222; font-family: "verdana" , "arial" , "helvetica" , sans-serif; font-size: 14px; line-height: 20px;">... </span> So clearly something was wrong and the array was not being sorted.<br />
<br />
But that's faulty troubleshooting, as one could tell by just trying to print the array <i>before</i> sorting. You would see basically the same thing.<br />
<br />
The reason for this is that when you do a System.out.println on any object, what you're actually doing is calling 'toString()'. If you are printing your own objects for which you've created nice methods that override the default toString, you get nicely formatted output. If you're using an ArrayList you get a nice, comma separated list enclosed in square brackets.<br />
<br />
Arrays are more primitive than that. Their default toString is just the one from Object, and it does nothing more than tell you where in the heap the object is located. This is good for verifying that something isn't null, but useless for determining the content.<br />
<br />
If you want to see the contents of the array, you've gotta do the work yourself, my friend. And it's not difficult at all. This, for instance, will work for any array of Objects that themselves support a reasonable version of 'toString':<br />
<br />
<pre style="background-color: white; font-family: 'Courier New';"><span style="font-size: x-small;"><span style="color: navy; font-weight: bold;">public static </span>String arrayToString(Object[] theArray) {
StringBuilder output = <span style="color: navy; font-weight: bold;">new </span>StringBuilder(<span style="color: green; font-weight: bold;">"["</span>);
<span style="color: navy; font-weight: bold;">for </span>(Object o:theArray){
<span style="color: navy; font-weight: bold;">if </span>(output.toString().length() > <span style="color: blue;">1</span>) {
output.append(<span style="color: green; font-weight: bold;">","</span>);
}
output.append(o);
}
output.append(<span style="color: green; font-weight: bold;">"]"</span>);
<span style="color: navy; font-weight: bold;">return </span>output.toString();
}</span><span style="font-size: 12pt;">
</span></pre>
<br />
<a href="https://gist.github.com/OOPUniversity/bada1c9cbd015de97b5b%EF%BF%BD">View code</a>J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.com0tag:blogger.com,1999:blog-8076032851736657838.post-47022734568588346002015-11-09T20:27:00.002-05:002015-11-09T20:27:57.104-05:00Indentation and style: A mild rant.People, people, people. When you're writing your code, you don't indent it and use brackets consistently in order to get brownie points. You do it to avoid long, long hours spent fruitlessly searching your code for something that should have been obvious. You don't do it so that your code looks pretty, you do it so that your code is clear.<br />
<br />
This was brought on by a snippet of code I found on pastebin that I rather wish I hadn't even seen. The indentation was all over the map and brackets were placed willy-nilly, and the guy wanted help. I wish he'd seen fit to help himself first. It's not like formatting code is even a difficult task. Any decent IDE will do it for you in no time flat. This can expose all sorts of issues, like that string of closing brackets down at the end that probably should have been interrupted by code that was, instead, nested at the deepest level.<br />
<br />
Back in the day, we'd run our code through a 'pretty printer' program before checking it in to source control. This didn't offer the same amenities we have now, but at least when someone checked out a module they didn't find themselves recoiling in horror until <i>after</i> they'd reviewed the logic.<br />
<br />
When you format your code consistently, you're not doing me a favor. You're doing yourself a favor. Future you will thank you for that, even as he or she is still kinda cheesed off that you chose to eat so many Doritos and didn't hit the gym enough.<br />
<br />J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.com0tag:blogger.com,1999:blog-8076032851736657838.post-3697572616537365262015-02-10T13:44:00.001-05:002015-02-10T22:22:31.366-05:00It's a SERIES OF TUBES!I've been struck in recent days by a number of posts over at /r/javahelp, all with the same basic theme. They've got some code, and it references a variable name that is declared elsewhere in the program. These nascent developers don't yet understand that just because you mention a variable in one place, that doesn't mean it's available elsewhere.<br />
<br />
It is fundamentally important to understand the issue of scope if you ever hope to write programs well. Where you declare things, and what keywords you use when you do so, have a huge effect on the visibility of your variables.<br />
<br />
For instance, I often see issues that boil down to an attempt at doing this:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">void multiplyTwoNumbers(int numberOne, int numberTwo) {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> int numberThree = numberOne * numberTwo;</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<br />
"It doesn't work" they say, or "it doesn't do anything". My friends, it does exactly what you told it to. It's just that you didn't tell it to do anything particularly useful. When this method is finished, it will have multiplied numberOne by numberTwo and assigned its value to numberThree. Then it's done.<br />
<br />
Some folks go a bit further:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">void callingMethod() {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> int numberThree;</span><br />
<span style="font-family: Courier New, Courier, monospace;"> multiplyTwoNumbers(5,10);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> System.out.println("See? It didn't work! " + numberThree);</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<br />
And they're right, it didn't.<br />
<br />
The reason is that the two variables named 'numberThree' are entirely independent of each other. One of them is really 'callingMethod->numberThree' and the other one is 'multiplyTwoNumbers->numberThree' and they have never met.<br />
<br />
Naming things the same is meaningless. It might help us to understand our code better, but as far as Java is concerned the variables might as well be called Ben and Jerry. Mmmm, Ben and Jerry.<br />
<br />
If you really want callingMethod->numberThree to take on the value you calculated in 'multiplyTwoNumbers' you need to explicitly lay it out. Just as you can't expect your sink to drain properly into the sewer system if you don't actually provide a continuous connection, you can't expect what one method does to just be known by another method.<br />
<br />
So make sure you declare multiplyTwoNumbers as an int. Make sure you actually <b>return</b> the value of numberThree at when it's done:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">int multiplyTwoNumbers(int numberOne, int numberTwo) {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> int numberThree = numberOne * numberTwo;</span><br />
<span style="font-family: Courier New, Courier, monospace;"> return numberThree;</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<br />
That will help. You've now installed the pop-up drain thingie in the bottom of the sink bowl. Let's finish the job:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">void callingMethod() {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> int numberThree;</span><br />
<span style="font-family: Courier New, Courier, monospace;"> numberThree = multiplyTwoNumbers(5,10);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> System.out.println("It verks! " + numberThree);</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<div>
<br /></div>
<div>
This is so important to understand. Local variables go away as soon as the local block (code between { and }) comes to and end. If you don't provide a method for the value to escape the block, it's going to go to the big heap in the sky.</div>
<div>
<br /></div>
<div>
Perhaps part of the problem is that people get confused by the fact that they can do this:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">public class Wizz {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> int wizzLevel = 0;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> public void bumpWizzLevel() {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> wizzLevel = wizzLevel + 1;</span></div>
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> public void displayWizzLevel() {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> System.out.println("Current level: " + wizzLevel);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<br />
Yes, that's perfect valid. In this case, 'wizzLevel' is an <i>instance variable</i> of the class Wizz. Every copy of Wizz you create has its own wizzLevel, and all methods within Wizz can reference or change it.<br />
<br />
The key of course, is to look at the brackets. Note that 'int wizzLevel' is inside the brackets for the class as a whole, so it's <i>in scope</i> everywhere within the class. <br />
<br />
The key takeaway is that when you want to understand where a variable is available to you, you need to understand that so long as you are still inside the same set of brackets where it was declared you should be good to go.<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">{</span><br />
<span style="font-family: Courier New, Courier, monospace;"> int outside;</span><br />
<span style="font-family: Courier New, Courier, monospace;"> {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> int inside; //outside is still available</span><br />
<span style="font-family: Courier New, Courier, monospace;"> {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> int wayInside; //inside and outside are still available</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;"> //wayInside is gone</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;"> //inside is gone</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<span style="font-family: Courier New, Courier, monospace;">//outside is gone</span>J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.com0tag:blogger.com,1999:blog-8076032851736657838.post-72257110537941967482014-12-21T22:37:00.001-05:002014-12-22T05:04:23.107-05:00Old McDonald had a File, IO IO IOOne of the most basic and common functions we programmers have to implement involves reading and writing data files. So get used to doing so. The good news is that Java is well equipped with many library functions for doing this. The bad news is exactly the same. There are many library functions, so many that you can get lost in them. In fact, just when we thought we had a handle on the 'java.io' package, along came 'java.nio' (New I/O) to cloud the picture even more.
Even an experienced programmer can get a little lost in the multiple classes that are in place for dealing with persistent data, and I certainly don't want to overwhelm my audience, so I'm going to stick to some basics.<br />
<br />
First off, I'm going to pretend that 'new I/O' never happened. I'm also going to offer you only a subset of all the functionality that's out there even in the java.io library. When it comes down to it, when you've got a file to read or write, you want to be able to just do so, without a lot of muss or fuss.<br />
<br />
I am going to have to assume that you're reasonably familiar with directories (or folders, if you must) and files as seen by your operating system. I'm going to assume that you understand what a text file is, and that you feel reasonably comfortable with viewing them or editing them with notepad, or UltraEdit, or whatever your choice of text editor might happen to be.<br />
<br />
First, a note on file types. There are of course a huge number of file formats out there, to support applications from AutoCAD to PhotoShop to Visual Studio, but all files can be pretty much divided into to major categories: Text and Other. Text files are broken down into lines, and many programs deal with them on a line by line basis. Other files tend to consist of plain old blocks of information, whether those be pixels for an image, or a song or movie, or quite literally anything else you can save.<br />
<br />
Java supports both major file types of course, and has objects specifically for dealing with each. When dealing with text files it's very convenient to read or write things one line at a time, so we have that ability in our libraries.<br />
<br />
We've used an object we call 'PersonData' before, and we'll make use of it again now. Suppose we had a file in which we had a bunch of last names and first names stored, for now we'll assume that last names and first names each appear on a line, so the file would look something like this:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">PEOPLE.TXT</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> Schmoe</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Joe</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Doe</span><br />
<span style="font-family: Courier New, Courier, monospace;"> John</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Smith</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Bill</span><br />
<br />
So we've got the information here to support three PersonData objects, all contained within a file called PEOPLE.TXT. <br />
<br />
If we wanted to read the names from this file and create PersonData objects, it's conceptually pretty simple:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">Open the file for reading</span><br />
<span style="font-family: Courier New, Courier, monospace;">As long as there's something to read</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Read a last name</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Read a first name</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Create a PersonData object with those values</span><br />
<br />
That makes sense, right?<br />
<br />
Enter the Scanner. The Scanner object is pretty new, and frankly I'm still not completely used to it. But it's so darned handy I have no excuse not to use it. The Scanner has several different constructors, but we're going to make use of the one that uses the File object right now.<br />
<br />
First, let's define the file that we intend to read. This sets us up for the next step:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">File personFile = new File("PEOPLE.TXT");</span><br />
<br />
Note that this isn't something that will fail, even if PEOPLE.TXT does not actually exist. Maybe we intend to create it next, or we want to test for its existence. The <i>File</i> object is handy that way.<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">Scanner personScanner = new Scanner(personFile);</span><br />
<br />
This can fail. If personFile refers to a non-existent file bad things can and will happen starting here. Proper code will be wrapped up in try/catch blocks as I discussed when we talked about exception handling.<br />
<br />
At this point we have covered the first line of our pseudo-code algorithm: "Open the file for reading". The next part was "As long as there's something to read", which a Scanner can handle quite easily:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">while (personScanner.hasNextLine()) {</span><br />
<br />
This loop will now run until we're out of lines. That's pretty convenient. Now let's extract the last and first names:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"> String lastName = personScanner.nextLine();</span><br />
<span style="font-family: Courier New, Courier, monospace;"> String firstName = personScanner.nextLine();</span><br />
<br />
Yes, there's a weakness or three here. We're making the assumption that our file is correctly formatted and complete, with two lines for every person. Good coding practice would include checking 'hasNextLine' in between those two lines and dealing with it if that isn't the case.<br />
<br />
We're actually almost done here. Once we've got the last name and the first name, we can go ahead and create a PersonData object:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"> PersonData personFromFile = new PersonData( firstName, lastName );</span><br />
<br />
At this point, technically we can end the loop. We've done the specified job, although realistically this is useless. There's not much point in reading a data file only to toss away the data. You'd want to do something with these 'personFromFile' objects, like adding them to a List or Map, or storing them in some other sort of data structure your program will use.<br />
<br />
But for now, we'll just pretend we're doing that and close down the file:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<span style="font-family: Courier New, Courier, monospace;">Scanner.close();</span><br />
<br />
And that's about all there is to reading text files since Java 7 came out. It was a bit more difficult before, when we had to create a couple of other objects in place of Scanner, and if the data included numbers or multiple items on one line it was even more involved.<br />
<br />
Let's say that the file was formatted like this instead:<br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">PEOPLE.TXT</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> Schmoe</span><span style="font-family: 'Courier New', Courier, monospace;"> Joe</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Doe </span><span style="font-family: 'Courier New', Courier, monospace;">John</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Smith </span><span style="font-family: 'Courier New', Courier, monospace;">Bill</span><br />
<div>
<br /></div>
<div>
That seems reasonable, right? It is, and it's pretty easy to deal with. All we'd need to do is change the following two lines from this:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> String lastName = personScanner.nextLine();</span><br />
<span style="font-family: Courier New, Courier, monospace;"> String firstName = personScanner.nextLine();</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
To this:</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> String lastName = personScanner.next();</span><br />
<span style="font-family: Courier New, Courier, monospace;"> String firstName = personScanner.nextLine();</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
And we will have accomplished our goal. We could also have done this:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> String lastName = personScanner.next();</span><br />
<span style="font-family: Courier New, Courier, monospace;"> String firstName = personScanner.next();</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace;"> String anythingLeftover = personScanner.nextLine();</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
What is important is to realize that 'nextLine' is critical to advance us from one line to the next, so we have to use it before we go through the loop again.<br />
<br />
Before I go, I also want to mention that Scanner is capable of reading not just Strings, but also any of the primitive data types as well. It supports nextInt(), nextDouble(), etc. It's also capable of reading more complicated input via the use of <i>Regular Expressions</i>, which are a huge topic in their own right. Regular Expressions essentially provide an entire language for matching complicated text, and an entire series of articles could no doubt be written just on that topic alone.</div>
<div>
<br /></div>
<div>
In our next episode, we'll talk about writing text files, which is just the reverse of what we've done here.</div>
J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.com0tag:blogger.com,1999:blog-8076032851736657838.post-2754452157293338212014-12-15T13:06:00.001-05:002014-12-15T13:06:55.686-05:00Inheritance Part 2: That's Rather Abstract, Isn't it?I hope you've been browsing through Java source code outside of your own and the small samples I've provided on this site. Reading and trying to understand code can only help you in the long run. You will encounter different code styles, you will see interesting data structures, API calls you didn't know existed, all sorts of stuff.<br />
<br />
Today I'm going to talk about something you might have seen, but if you haven't, it's no big deal. It is the keyword <i>abstract</i>.<br />
<br />
We use abstract as part of the definition of a class, which indicates that while it is in fact a valid class file, nobody is allowed to create an object of that type. That doesn't mean that it's useless though. Remember, we have inheritance on our side. You can create <i>concrete</i> classes (concrete is just the opposite of abstract, indicating a class from which you can create objects. No special keyword is needed for that) that extend abstract classes all you want.<br />
<br />
We also use abstract as part of method signatures when we want to create the idea of a particular method call but wish to defer the actual implementation of said method to our concrete classes. This is similar in concept to interfaces, and sometimes it's more of a personal decision as to which you will use.<br />
<br />
You see a lot of abstract classes in use when you look through <i>frameworks</i>, which are basically bodies of code designed to accomplish some function but with the details left up to the final developer. There are business frameworks, logging frameworks, GUI frameworks, reporting frameworks, the list is very long. Usually the trigger for creating a framework is when someone realizes they've just written the same thing for the fifth or tenth time, and that the differences between the various programs are relatively minor. Maybe you query a database, format a report and write it to a file, and it's always the same except for the details of which fields you look for and print.<br />
<br />
This is a great application for abstract classes. Let's take a look at a simple one:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">public abstract class Report {</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<br />
Well, that's about as simple as it gets. To be fair it's also about as useless as it gets but never fear, we'll fill in some details later. Actually it's not entirely useless. You might want to have a set of classes that all share a common base class so that you can collect them into a Collection of some sort, although you could also make this work with an interface. Abstract classes really come into their own when you include some code within them. So let's write something.<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">public abstract class Report {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> public abstract void GenerateOutputLine(String dataLine);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> public abstract String ReadData();</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> public void runReport() {</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> String dataLine = null;</span><br />
<span style="font-family: Courier New, Courier, monospace;"> while( null != ( dataLine = ReadData() ) ) {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> GenerateOutputLine(dataLine);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;"> </span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<div>
<br /></div>
OK, that was simple enough. We have defined not only our abstract Report class, but made it do a little bit of work for us. It calls ReadData until that method returns a null, and then takes the value returned from ReadData and passes it to GenerateOutputLine. Of course, you can't actually run this report, you need to create at least one concrete class based on it. That could be a simple test driver designed to make absolutely certain that your framework behaves properly with known data. It could be something that reads from one file and writes to another, which would basically give you a 'copy file' command. It could be something that reads one file, does some calculations or modifications, and then spits out the changed data. The options are nearly endless, despite the fact that this is a highly simplified example.<br />
<br />
Let's write a simple test driver:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">public class ReportTester extends Report {</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> public static void main(String[] args) {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> ReportTester rt = new ReportTester();</span><br />
<span style="font-family: Courier New, Courier, monospace;"> rt.runReport();</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<span style="font-family: Courier New, Courier, monospace;"> String [] dataLines = {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "one", "two", "three", "four", "five"</span><br />
<span style="font-family: Courier New, Courier, monospace;"> };</span><br />
<span style="font-family: Courier New, Courier, monospace;"> int lineNumber = 0;</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> public void GenerateOutputLine(String dataLine) {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> System.out.println(dataLine);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> public String ReadData() {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> String toReturn = null;</span><br />
<span style="font-family: Courier New, Courier, monospace;"> if (lineNumber < dataLines.length) {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> toReturn = dataLines[ lineNumber++ ] ;</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;"> return toReturn;</span><br />
<span style="font-family: Courier New, Courier, monospace;"> } </span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<br />
Now if we were to run 'ReportTester' we'd get the output:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">one</span><br />
<span style="font-family: Courier New, Courier, monospace;">two</span><br />
<span style="font-family: Courier New, Courier, monospace;">three</span><br />
<span style="font-family: Courier New, Courier, monospace;">four</span><br />
<span style="font-family: Courier New, Courier, monospace;">five</span><br />
<br />
The main driver of the program is still in that 'Report' superclass, but the implementation details have been kept in ReportTester. We run the code in Report, and it calls the methods it finds in ReportTester to do the work. ReportTester itself is quite simple. In addition to a simple main that does nothing more that create ReportTester and run it (actually running that method from the superclass Report), it defines the specific implementations for our two abstract methods. One method does nothing more than write to the console and I hope I don't need to explain that. The other goes through an array of Strings, returning the next one in the array and increasing the index value each time it's invoked until it reaches the end of the list, at which time it returns a null which triggers the end of the loop in 'runReport'.<br />
<br />
This is of course tremendous overkill for a program of this size, but as your projects get more involved, the ratio of abstract code to concrete code is likely to change quite a bit. System maintenance gets easier and faster, and your software gets more robust. After all, a bug fix to a framework may take care of issues across several dozen different specific implementations of different reports.<br />
<br />
I will of course revisit this topic later, because we've only scratched the surface of the possibilities brought on by object orientation. With enough small components intelligently built, one can assemble new programs almost like putting together Tinker Toys or Lego. One's systems can be defined in large part by configuration files, and changed easily at will, all without writing, testing or deploying new code.<br />
<br />
<br />J.D. Lukehttp://www.blogger.com/profile/11008806360562762840noreply@blogger.com0