<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Wayne Olson]]></title><description><![CDATA[No Description]]></description><link>https://wayneo.co/</link><image><url>https://wayneo.co/favicon.png</url><title>Wayne Olson</title><link>https://wayneo.co/</link></image><generator>Ghost 2.9</generator><lastBuildDate>Wed, 23 Aug 2023 15:41:46 GMT</lastBuildDate><atom:link href="https://wayneo.co/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Capstone Prep Week 2: Team Intros, Testing and Redux]]></title><description><![CDATA[As Capstone prep continues I've noticed a two-fold sense of both progress and growing confidence: progress towards definitive mileposts (the start of Capstone and the start of a new career), and the growing sense that yes, I can do this.

In the almost two years from when I first enrolled in Launch School to finishing its Core Curriculum, there was always this sense that a new career was out there at the end of the journey; I just didn't know when that would be given the self-paced, mastery-base]]></description><link>https://wayneo.co/capstone-prep-week-2-team-intros-testing-and-redux/</link><guid isPermaLink="false">Ghost__Post__637d8ad8661baa059b30fd5c</guid><category><![CDATA[Launch School]]></category><dc:creator><![CDATA[Wayne Olson]]></dc:creator><pubDate>Wed, 23 Nov 2022 02:53:50 GMT</pubDate><content:encoded><![CDATA[<p>As Capstone prep continues I've noticed a two-fold sense of both progress and growing confidence: progress towards definitive mileposts (the start of Capstone and the start of a new career), and the growing sense that <em>yes, I can do this</em>.</p><p>In the almost two years from when I first enrolled in Launch School to finishing its Core Curriculum, there was always this sense that a new career was out there at the end of the journey; I just didn't know when that would be given the self-paced, mastery-based nature of the program, which has no time-based mileposts other than those that might be self-imposed. And it's also certainly the case that one is just an <em>aspiring</em> software engineer while going through the program, rather than a software engineer full stop.</p><p>But by this point things are qualitatively different: I now have definitive mileposts in sight as well as a sense that, yes, finally and after all this time, I can actually change my <a href="https://www.linkedin.com/in/wayneoco/">professional title</a> to software engineer.</p><h3 id="meeting-my-team">Meeting My Team</h3><p>This week I had the opportunity to meet my teammates for the first time. Launch School has a very active Slack community which gives the opportunity to meet other students while making one's way through the program, but I had never come across any of my teammates previously. And not knowing anyone with whom you're going to be spending a great deal of time over the next several months brings a bit of curiosity (maybe even some anxiety) with it– Will we get along well? What if I'm not as good as my teammates? What if we have different levels of motivation? etc etc.</p><p>All in all, we had a productive meeting getting to know each other, and I think everything will work out just fine. Sure, we may hit some inevitable snags along the way as we learn to work together, but that's not unexpected when forming a new team. The most important thing is that it takes a certain level of excellence to complete the Core Curriculum with high enough marks to satisfy Capstone's admission requirements, which we've all attained, and a willingness to learn together and support each other through these next several months.</p><h3 id="testing-testing-and-more-testing">Testing, Testing and More Testing</h3><p>This week I was knee deep into JavaScript testing on both the backend and the frontend, learning about unit, integration and end-to-end (E2E) testing.</p><p>As can be gathered from the name, unit testing focuses on isolating individual components or functions (i.e, units) of an application. This means that a test completely isolates a single part from the rest of the application, limiting or removing any side effects (like querying and manipulating a database) as much as possible. Since the backend application we were working through was essentially an API for querying a database, our course opted for integration tests over unit tests, since there really wasn't any functionality to our backend app that didn't also involved querying a database.</p><p>To test our React-based frontend we designed unit tests to test the rendering of individual components. One point of interest is that in testing how React components are rendered, we learned how to mock user input like clicking a button or entering text into an input field using the testing utilities from <code>@testing/library</code>. Pretty cool…</p><p>To further test our React frontend we also learned how to use <a href="https://cypress.io">Cypress</a> for complete end-to-end (E2E) testing. In contrast to unit tests, which isolate and test single components, or integration tests which test multiple components together, E2E tests test the entire application as a whole. Learning about Cypress (and E2E testing as a whole) was probably the most interesting part, as tests are run in the browser and mock the user experience <em>from the user's perspective</em>. In other words, just as we were able to mock user input when designing unit tests for individual React components, we created tests in Cypress that mocked not only user input but user flow through the application we built (a simple note logging app). To boot, Cypress also has a nice GUI that displays the testing flow in the browser as it happens, which makes poking around an application to check the state of components at specific times rather easy.</p><h3 id="state-management-with-redux">State Management with Redux</h3><p>When I was first learning React during the 'downtime' I had between Core and the beginning of prep, one of the issues I ran into as I was building my own application was how <em>un</em>manageable managing state can become as the depth and complexity of an application grows. As that added complexity continues to pile on top of itself, all of sudden you've got all sorts of state to manage, while passing all sorts of state through all sorts of component props, while simultaneously trying to avoid unnecessary re-renderings. It gets a bit messy, to say the least.</p><p>If only there were a way to simplify state management…</p><p><em>Well hello there, <a href="https://redux.js.org/">Redux</a>.</em></p><p>Redux is one of those things I really wish I had known about earlier. The beauty of it is that it abstracts the entirety of state management to a single JavaScript object called a <strong>store</strong>. So rather than leaving it to components within an application to manage state, all aspects of an application's state are now managed in a centralized location, the Redux store. From there, components simply hook into the store whenever state needs to be updated or retrieved.</p><h3 id="finishing-up-full-stack-review">Finishing Up Full Stack Review</h3><p>This week is a bit busier than usual, with Thanksgiving coming up and two kids home for fall break, so time for Capstone prep is in short supply this week. Plus, I'm moving soon, which I also need to start prepping for this week, which compresses available time a bit more as well.</p><p>All of that said, I've got two more units (React router, custom hooks and Typescript) to finish in order to move to the next part of prep, which focuses on version control and cloud networking. I'd <em>like</em> to finish these two units this week, but given the aforementioned issues with my schedule, I'm not sure that'll happen.</p><p>But as always, we press forward, doing our best…</p><p><em>This article is part of a series writing about my experience going through Launch School's Capstone program.</em></p><ul><li><a href="https://wayneo.co/capstone-prep-week-0-getting-started/">Capstone Prep Week 0: Getting Started...</a></li><li><a href="https://wayneo.co/capstone-prep-week-1-building-web-apps-with-react-express-mongodb/">Capstone Prep Week 1: Building Web Apps with React, Express, MongoDB</a></li></ul>]]></content:encoded></item><item><title><![CDATA[Capstone Prep Week 1: Building Web Apps with React, Express, MongoDB]]></title><description><![CDATA[Capstone prep is officially underway as of this past week, and with that you could really feel the momentum picking up as we barrel towards January 2nd, the official start date of the January '23 cohort. Friday we received all sorts of information related to our Capstone experience– expectations for communicating with staff, the daily schedule and the syllabus for each of the 17 weeks of the program, to name a few.

We also received our team assignments– the people with whom I'll be learning thr]]></description><link>https://wayneo.co/capstone-prep-week-1-building-web-apps-with-react-express-mongodb/</link><guid isPermaLink="false">Ghost__Post__63721165661baa059b30fd42</guid><category><![CDATA[Launch School]]></category><dc:creator><![CDATA[Wayne Olson]]></dc:creator><pubDate>Mon, 14 Nov 2022 10:04:10 GMT</pubDate><content:encoded><![CDATA[<p>Capstone prep is officially underway as of this past week, and with that you could really feel the momentum picking up as we barrel towards January 2nd, the official start date of the January '23 cohort. Friday we received all sorts of information related to our Capstone experience– expectations for communicating with staff, the daily schedule and the syllabus for each of the 17 weeks of the program, to name a few.</p><p>We also received our team assignments– the people with whom I'll be learning throughout the program and, starting in the second half of the program, building a project that tackles a real-world software engineering problem. Working with a team is a core part of Capstone, as it models the experience of a working software engineer– working with a group of people to research a problem domain and ultimately build a software application that solves a specific problem within that domain. And of course that brings with it all the various complexities that come with working on a team– navigating potential personality conflicts and differences in communication style, learning to debate trade offs and solutions to problems and ultimately learning to design and code an application together.</p><p>At the end of the day though I think everything will be just fine– great, even. The bar to get into Capstone is rather high, which means you can expect that your teammates will generally be of high intellectual caliber, and Launch School tends to naturally attract the type of student you want to be around– studious, committed and highly motivated with a positive attitude.</p><h2 id="reviewing-full-stack-web-development">Reviewing Full-stack Web Development</h2><p>I spent this first week reviewing topics in full-stack web development– frontend development with React, backend development with Node.js and Express, the HTTP request and response cycle, creating RESTful APIs for resource management, and data storage with MongoDB.</p><p>Fortunately all of this was review– HTTP and REST APIs were covered in <a href="https://launchschool.com/courses">Core</a>, and I spent all of September and October learning React, Express and MongoDB as part of my 'pre-Capstone prep' work. And it's a good thing, too, as I'd otherwise need to spend a lot more time trying to understand some of the tougher concepts in React– specifically state management with <code>useState</code>, triggering side effects with <code>useEffect</code>, and how they each relate to component rendering and re-rendering (I'm sure that anyone who's learning React has improperly managed state such that it triggers an infinite render loop at least once in their journey).</p><p>One cool thing about the work this past week was discovering <a href="https://fly.io/">Fly.io</a>, a PaaS Heroku alternative. In contrast to Heroku, which recently shuttered its free plans, Fly.io has a very workable free tier (including Postgres, if needed) which is great for students and small projects. To boot, Fly.io requires much less configuration to deploy to production, and the performance seems to me to be a bit improved compared to what was available on Heroku's free tier.</p><p><em>And the people rejoice…</em></p><h2 id="discovering-the-convenience-of-scripts-in-packagejson">Discovering the Convenience of Scripts in package.json</h2><p>One thing I learned this week – which I suppose you could say has been sitting under my nose undiscovered until a few days ago, so to speak – is that you can configure scripts in <code>package.json</code> to make your development life easier, and sometimes by orders of magnitude easier.</p><p>Yes, I've known about configuring single command scripts for things like starting up a server or running a server from Nodemon. But what did not occur to me is that you can configure <em>multi-step processes under a single script</em>.</p><p>For example, the process of packaging code for deployment to production is a bit tedious– first you create a production build of the frontend code, and then you have to copy the production build to the backend to be served by Express. Then the entire backend needs to be deployed to production, whether that be Heroku or Fly.io or elsewhere. To do this manually entails submitting a command, waiting for the production build to complete, copying a directory and then submitting a final command for deployment.</p><p>But wait! Let's just throw all of that into a single script and call it a day. Here's an example:</p><pre><code class="language-javascript">// package.json
"scripts": {
    "build:ui": "rm -rf public &amp;&amp; cd ../frontend &amp;&amp; npm run build &amp;&amp; cp -r build ../backend &amp;&amp; cd ../backend &amp;&amp; mv build public",
    "deploy": "fly deploy",
    "deploy:full": "npm run build:ui &amp;&amp; npm run deploy"
  },
</code></pre><p>Actually, as you can see above it's really 3 commands: one to build the UI, one to deploy to production, and one final command that combines both the build and deploy commands together. So to build the frontend and then deploy the entire application to production, just run <code>npm run deploy:full</code> and that whole multi-layer process becomes just a single step.</p><h2 id="starting-javascript-unit-testing%E2%80%A6">Starting JavaScript Unit Testing…</h2><p>Today I started learning about unit testing using Jest and will finish that up tomorrow. Conceptually it seems to me to be similar to testing in Ruby (which I learned using Minitest), which at its core boils down to testing results against assertions of what the expected result should be.</p><p><em>This article is part of a series writing about my experience going through Launch School's Capstone program.</em></p><ul><li><a href="https://wayneo.co/capstone-prep-week-0-getting-started/">Capstone Prep Week 0: Getting Started...</a></li></ul>]]></content:encoded></item><item><title><![CDATA[Capstone Prep Week 0: Getting Started]]></title><description><![CDATA[Finishing Core

This week, with signed ISA and deposit submitted, I officially joined the next cohort of Launch School's highly regarded Capstone program in software engineering. Officially the program begins on January 2nd, but preparation begins now with about 6 weeks or so worth of prep material to go through.

But let's backtrack for a moment, since it's been some time since my last update.

On August 31st, I finished Launch School's Core Curriculum. I spent about two months going through th]]></description><link>https://wayneo.co/capstone-prep-week-0-getting-started/</link><guid isPermaLink="false">Ghost__Post__6367f804661baa059b30fd2d</guid><category><![CDATA[Launch School]]></category><dc:creator><![CDATA[Wayne Olson]]></dc:creator><pubDate>Sun, 06 Nov 2022 18:13:19 GMT</pubDate><content:encoded><![CDATA[<h1 id="finishing-core">Finishing Core</h1><p>This week, with signed ISA and deposit submitted, I officially joined the next cohort of Launch School's highly regarded <a href="https://launchschool.com/capstone">Capstone</a> program in software engineering. Officially the program begins on January 2nd, but preparation begins <em>now</em> with about 6 weeks or so worth of prep material to go through.</p><p>But let's backtrack for a moment, since it's been some time since my last update.</p><p>On August 31st, I finished Launch School's Core Curriculum. I spent about two months going through the final course, JS230, which covers the DOM and asynchronous JavaScript. It's a challenging course– no more difficult than any other of Launch School's typical in depth, rigorous courses, but man it is <em>long</em>. You really have to go into the course with your mental stamina in a good place, because getting through the sheer volume of topics, exercises and mini projects is no small feat. At the end though, you come out with a solid base for full stack development.</p><p>All in all, it took almost two years to work my way through Core, which also includes a 7-month break at the end of 101 and about 6 weeks of redoing 101 once I returned. So after removing the breaks and catch up time, it took about a year of focused study to complete the curriculum. Time commitments varied, but for those wondering, if we consider full-time study to be 100%, my time commitment throughout Core was probably around 50-70%.</p><p>Once completed, per Launch School's recommendation I took a course covering full stack development using the MERN stack– MongoDB (for the database), Express (for the backend server), React (for the frontend) and Node.js (for the backend). I spent all of September working my way through that course, followed in October by implementing what I learned by building my own full stack app— a contact manager with some smart functionality built-in (i.e., a personal CRM that reminds you to contact people at specific intervals while also making smart suggestions for people you <em>might</em> want to contact but haven't thought about). That project still has some loose ends to tie up, so it's not quite in a 'show-ready' state yet. I'd <em>like</em> to finish it, but with Capstone prep now underway, I'm not sure I'll have time to wrap it up.</p><h1 id="beginning-capstone-prep">Beginning Capstone Prep</h1><p>To have the best Capstone experience, Launch School requires students to go through a large number of prep materials <em>before</em> Capstone starts, with the anticipated time being about 6 weeks of full-time study. So while Capstone itself is about 4 months, the <em>real</em> time commitment is about 6 months when you account for Capstone prep. And that still doesn't account for an additional 1-3 months for the job search post-Capstone. So the optimal Capstone experience is roughly a 7-9 month, full-time commitment from start to job placement.</p><p>One interesting observation about the prep materials: the very first thing on the list is learning how to be a good teammate. Through Capstone you work on a team, which models the way complex software is built– as part of a team. In one sense this topic has nothing to do with software engineering; yet in another, it has everything to do with it. Software isn't built in a vacuum, and I really appreciate that Launch School starts our Capstone journey by focusing our attention on how to work well with others, because the reality is that your experience with your team does impact your ability to produce good software.</p><p>For now I've read through the required articles, watched the required video, and am currently 'reading' through the audiobook version of <a href="https://www.amazon.com/Give-Take-Helping-Others-Success-ebook/dp/B00AFPTSI0">Give and Take: Why Helping Others Drives Our Success</a> by Adam Grant.</p><p>Next on the list is a course on full stack development, which I'm currently working through. This course covers the MERN stack, which I learned in September after I finished Core, so for now it's simply been a review of what I've already learned. Some topics to be covered that I <em>didn't</em> learn before will be testing using Jest, state management with Redux (and thunks by extension), and Typescript.</p><p>Some other topics to be covered during prep:</p><ul><li>Go</li><li>Version control and cloud networking</li><li>Data structures and algorithms</li><li>Ruby on Rails (optional if time allows)</li></ul><p>All in all, I'm excited to embark on this part of the journey toward a career in software engineering. Stay tuned…!</p>]]></content:encoded></item><item><title><![CDATA[Current Launch School Progress]]></title><description><![CDATA[It's a bit surreal, but I am just about to complete Launch School's Core Curriculum in software engineering. As of August 8, 2022, here's a summary of my current progress:


 * Programming and Backend Development
   
   * ✅ RB101: Programming Foundations (Ruby)
   * ✅ RB109: Assessment (Written Exam & Live Coding Interview)
   * ✅ RB120: Object Oriented Programming (Ruby)
   * ✅ RB129: Assessment (Written Exam & Live Coding Interview)
   * ✅ RB130: Ruby Foundations: More Topics
   * ✅ RB139: Ass]]></description><link>https://wayneo.co/current-launch-school-progress/</link><guid isPermaLink="false">Ghost__Post__62f0c0feb63ab590f6a1a14c</guid><category><![CDATA[Launch School]]></category><category><![CDATA[Now]]></category><dc:creator><![CDATA[Wayne Olson]]></dc:creator><pubDate>Mon, 08 Aug 2022 07:56:17 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1588345921523-c2dcdb7f1dcd?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDg4fHxwcm9ncmVzcyUyMGJsYWNrJTIwYW5kJTIwd2hpdGV8ZW58MHx8fHwxNjU5OTQ1MzA4&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://images.unsplash.com/photo-1588345921523-c2dcdb7f1dcd?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxMTc3M3wwfDF8c2VhcmNofDg4fHxwcm9ncmVzcyUyMGJsYWNrJTIwYW5kJTIwd2hpdGV8ZW58MHx8fHwxNjU5OTQ1MzA4&ixlib=rb-1.2.1&q=80&w=2000" alt="Current Launch School Progress"/><p>It's a bit surreal, but I am just about to complete Launch School's <a href="https://launchschool.com/courses">Core Curriculum</a> in software engineering. As of August 8, 2022, here's a summary of my current progress:</p>
<ul>
<li><strong>Programming and Backend Development</strong>
<ul>
<li>✅ RB101: Programming Foundations (Ruby)</li>
<li>✅ RB109: Assessment (Written Exam &amp; Live Coding Interview)</li>
<li>✅ RB120: Object Oriented Programming (Ruby)</li>
<li>✅ RB129: Assessment (Written Exam &amp; Live Coding Interview)</li>
<li>✅ RB130: Ruby Foundations: More Topics</li>
<li>✅ RB139: Assessment (Written Exam)</li>
<li>✅ LS170: Networking Foundations</li>
<li>✅ LS171: Assessment (Written Exam)</li>
<li>✅ RB175: Networked Applications (Ruby, Sinatra)</li>
<li>✅ LS180: Database Foundations (PostgreSQL)</li>
<li>✅ LS181: Assessment (Written Exam)</li>
<li>✅ RB185: Database Applications (Ruby, Sinatra, PostgreSQL)</li>
</ul>
</li>
<li><strong>Frontend Development</strong>
<ul>
<li>✅ LS202: HTML and CSS</li>
<li>✅ JS210: Fundamentals of JavaScript for Programmers</li>
<li>✅ JS211: Assessment (Written Exam)</li>
<li>✅ LS215: Computational Thinking and Problem Solving</li>
<li>✅ LS216: Assessment (Live Coding Interview)</li>
<li>✅ JS225: Object Oriented JavaScript</li>
<li>✅ JS229: Assessment (Written Exam &amp; Project-based Assessment)</li>
<li>✅ JS230: DOM and Asynchronous Programming with JavaScript</li>
<li><span style="color: #ccc;">JS239: Assessment (Written Exam &amp; Project-based Assessment)</span></li>
</ul>
</li>
</ul>
<p>As you can see above, I have completed all courses through JS230, which leaves only JS239 to complete the Core Curriculum. JS239 is comprised of two assessments — one written and one project-based — for which I'll begin preparing this week. Launch School assessments are <em>tough</em>, and you have to get 90% or higher in order to pass them. At Launch School there is no such thing as 'good enough'; you have to master the material, and only then can you progress to the next course.</p>
<p>You might be wondering what comes next, once I complete the Core Curriculum. Launch School has a finishing program called <a href="https://launchschool.com/capstone">Capstone</a>, and I'll be joining the Winter '23 cohort in January.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[JS230 Side Project: Website Redesign]]></title><description><![CDATA[Using what I learned in JS230 to redesign my website.]]></description><link>https://wayneo.co/js230-side-project-website-redesign/</link><guid isPermaLink="false">Ghost__Post__62f086eeb63ab590f6a1a121</guid><category><![CDATA[Launch School]]></category><category><![CDATA[Personal]]></category><dc:creator><![CDATA[Wayne Olson]]></dc:creator><pubDate>Sun, 07 Aug 2022 03:50:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Recently I decided to rebuild my website, as I thought it would be an interesting challenge given all of the frontend work I had been doing for JS230 (DOM and Asynchronous Programming with JavaScript), the final course in Launch School's Core Curriculum. And as it turns out, I'll need to put together a personal website as part of the prep work for entering Launch School's <a href="https://launchschool.com/capstone" title="Capstone">Capstone</a> program, so it looks like I'm ahead of the curve on work I'll need to do anyway. <sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup></p>
<p>For years I had been using the publishing platform <a href="https://ghost.org" title="Ghost">Ghost</a> to power some version of a blog and personal website. However, I had never been in a position to customize it to any meaningful extent; I simply picked a theme and then stumbled my way through making basic CSS edits via Ghost's 'code injection' feature. This feature gives you a setting (by way of a text box) that allows you to override your theme's CSS by 'injecting' your custom edits into your website's <code>&lt;head&gt;</code> element. But if I wanted to have full control over the structure and design, I would need to know JavaScript as well as the templating language Ghost uses, <a href="https://handlebars.js" title="Handlebars.js">Handlebars.js</a>.</p>
<p>Lucky me, as I've been learning just that — extensive JavaScript as well as Handlebars — so I set out to build a custom Ghost theme from scratch.</p>
<h2 id="designing-a-custom-theme">Designing a Custom Theme</h2>
<p>Well, to say that I designed a theme from scratch isn't entirely true. I used a bare bones starter template, <a href="https://github.com/curiositry/undefined-ghost-theme" title="Undefined">Undefined</a>, which provides the essential structure of a theme for developers but without any styling. Think of it like plain HTML documents that give you just enough markup to get a minimal website up and running. The difference is that these are <code>.hbs</code> (Handlebars) files that allow you to write Handlebars template expressions inside what would otherwise be plain HTML documents.</p>
<p>Towards the end of JS230, the coursework introduces templating with JavaScript using Handlebars.</p>
<p>Now that I had experience with Handlebars I was able to make sense of both the structure and functionality of templates in Ghost, in addition to implementing the more sophisticated CSS I had been learning. In particular I was able to understand how partial templates work, create my own templates, and use and create helpers to add functionality to the design. These are all critical elements for piecing together a well-structured, highly functional Ghost theme.</p>
<p>And three to four days later I had created more or less the design you see now.</p>
<h2 id="switching-to-gatsby-learning-react-and-graphql-and-just-in-time-learning">Switching to Gatsby, Learning React and GraphQL, and Just in Time Learning</h2>
<p>It turned out that redesigning the Ghost frontend was rather painless. Launch School's coursework is both rigorous and thorough, and I had recently been doing a lot of frontend work as part of JS230, so I was well prepared to tackle designing Handlebars-based templates. I won't say it was <em>too</em> easy, but it was easy enough that I wanted to push myself a bit further with the redesign.</p>
<p>So what could I do?</p>
<p>Out of the box, Ghost gives you both the backend CMS and the frontend design, just as other CMSs like Wordpress. But it also has a solid API that enables you to decouple the CMS and use a different framework for the frontend (using the CMS as what is often called a <em>headless</em> CMS). In other words, you could host an independent frontend and then source content from your Ghost installation to that frontend via the Ghost API, limiting use of Ghost purely to content management.</p>
<p>There are lots of ways to run a headless CMS. Years ago I had come across <a href="https://gatsbyjs.com" title="Gatsby">Gatsby</a>, and while it was intriguing because of all of the benefits that come with <a href="https://jamstack.org/why-jamstack/" title="JAMstack">JAMstack</a> architecture and <a href="https://www.cloudflare.com/learning/performance/static-site-generator/" title="static site generators">static site generators</a>, at the time I just didn't know enough to build a frontend using it. That intrigue was reignited earlier this year after watching <a href="https://www.youtube.com/watch?v=3xNVJu1mIY0" title="a presentation about Gatsby">a presentation about Gatsby</a> from a Launch School alumnus who's an engineer at Gatsby. It also turned out that Gatsby has hired <em>a lot</em> of Launch School graduates over the years, so I thought it would be an interesting project to learn Gatsby and see if I could implement it as the frontend of a headless Ghost installation.</p>
<p>To make it a little easier, Ghost has a <a href="https://www.gatsbyjs.com/starters/TryGhost/gatsby-starter-ghost" title="Gatsby starter template">Gatsby starter template</a> that I used as a starting point. However, as you can see in the <a href="https://gatsby.ghost.org/" title="demo">demo</a>, the starter template is quite different from the design you see now.</p>
<p>In order to reimplement my design using Gatsby I had to learn React and GraphQL, neither of which I had any previous experience with. But that's the beauty of Launch School: you don't just learn languages and syntax; you learn <em>how to learn</em>. Because of Launch School's pedagogical approach, which focuses on mastery of fundamental concepts in software engineering as well as <em>how to learn</em> those concepts, it unlocks a skill called <a href="https://medium.com/launch-school/just-in-time-learning-f6a10886ddfe" title="'Just in time' (JIT) learning">'Just in time' (JIT) learning</a>, which enables one to learn a new language to a productive level in a very short period of time.</p>
<p>Of course, that doesn't mean I became an expert in React and GraphQL overnight, nor is that the intent of JIT learning. What it did though was enable me to learn enough React and GraphQL to, in a relatively short period of time, redesign my website with a Gatsby frontend. Using the starter template as a guide, along with a combination of Gatsby, React and GraphQL documentation, this process took about a week and a half.</p>
<h2 id="building-features-with-javascript-and-css">Building Features with JavaScript and CSS</h2>
<p>One of the cool things about being at the end of JS230 is being able to build interactive features using JavaScript and CSS. Here are some of the features I was able to implement using what I learned from JS230:</p>
<table>
<thead>
<tr>
<th>Feature</th>
<th>Implementation</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td>Responsive Menu</td>
<td>CSS media query</td>
<td>Depending on the size of the viewport, the navigation menu is displayed as a row of links (desktop) or is hidden with a hamburger menu icon in its place (mobile).</td>
</tr>
<tr>
<td>Display Mobile Navigation</td>
<td>JavaScript event interface</td>
<td>Once the standard navigation menu is hidden on mobile devices, I used JavaScript event listeners and handlers to display and hide the navigation links.</td>
</tr>
<tr>
<td>Post Feed Animation</td>
<td>JavaScript event interface</td>
<td>I used JavaScript event listeners and handlers to display and hide the double chevron icon on hover.</td>
</tr>
<tr>
<td>Contact Form</td>
<td>Asynchronous JavaScript</td>
<td>I use a service called EmailJS which requires use of an asynchronous function to send form data upon submission. It also required learning how to integrate Google’s reCATPCHA service so that a successful HTTP response was sent only upon submission of the reCAPTCHA form.</td>
</tr>
<tr>
<td>Contact Form Response Message</td>
<td>DOM and Asynchronous JavaScript</td>
<td>Depending on the response received from the EmailJS server, I triggered a ‘failure’ alert window or used DOM elements to replace the form with a ‘success’ message.</td>
</tr>
</tbody>
</table>
<p>Nothing earth-shattering, but it demonstrates on a practical level some of what I’ve learned in JS230. The key thing is that I went from knowing essentially nothing about frontend design to having full control over my website using rather sophisticated technologies.</p>
<h2 id="looking-ahead">Looking Ahead</h2>
<p>For now I’ll leave my website as is, as I need to start preparing for the JS239 assessments— one written and one project-based. However, at some point I’d like to add some additional features such as:</p>
<ul>
<li>Dark mode</li>
<li><a href="https://www.algolia.com/" title="Algolia">Algolia</a> powered search</li>
<li>A ‘Projects’ directory</li>
</ul>
<p>Of course, that last item assumes I have projects to showcase. I’ll spend this fall engaged in Capstone prep work, and I plan to include some projects as part of that work to display here.</p>
<p>Thanks for reading, and if you have any feedback or questions about the new design, don’t hesitate to leave a comment below or drop me a note <a href="https://wayneo.co/contact">here</a>.</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>I'll be entering the Winter '23 Capstone cohort, which starts in January. <a href="#fnref1" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown--></hr>]]></content:encoded></item><item><title><![CDATA[Finding My Way Back to Launch School]]></title><description><![CDATA["Your background looks great... you may start the paid courses at your convenience."

With that virtual nod from Launch School's founder, Chris, I officially enrolled in Launch School's Core Curriculum for software development. I had just finished the free prep course and was ready to embark on the next phase of the journey that Launch School calls the slow path for studious learners.

It was October 2020, and I was ready.

And more importantly, I was ready to set out on the path to becoming a s]]></description><link>https://wayneo.co/finding-my-way-back-to-launch-school/</link><guid isPermaLink="false">Ghost__Post__62e9d4bbf3103934aeef36b6</guid><category><![CDATA[Launch School]]></category><dc:creator><![CDATA[Wayne Olson]]></dc:creator><pubDate>Sun, 16 Jan 2022 02:11:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1441039995991-e5c1178e605a?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDF8fG1vdW50YWluJTIwYmxhY2slMjBhbmQlMjB3aGl0ZXxlbnwwfHx8fDE2NTk0MDI3MzQ&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<blockquote>"Your background looks great... you may start the paid courses at your convenience."</blockquote><img src="https://images.unsplash.com/photo-1441039995991-e5c1178e605a?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxMTc3M3wwfDF8c2VhcmNofDF8fG1vdW50YWluJTIwYmxhY2slMjBhbmQlMjB3aGl0ZXxlbnwwfHx8fDE2NTk0MDI3MzQ&ixlib=rb-1.2.1&q=80&w=2000" alt="Finding My Way Back to Launch School"/><p>With that virtual nod from Launch School's founder, Chris, I officially enrolled in Launch School's <a href="https://launchschool.com/courses">Core Curriculum</a> for software development. I had just finished the free prep course and was ready to embark on the next phase of the journey that Launch School calls <em>the slow path for studious learners</em>.</p><p>It was October 2020, and I was <em>ready</em>.</p><p>And more importantly, I was ready to set out on the path to becoming a software engineer. Excited and motivated, I was starting this new journey with as much energy and focus as I've ever had.</p><p>But then something happened. About two weeks into the first course, and just as I was about to complete the second to last lesson, I needed to devote a significant amount of mental energy and bandwidth to dealing with some personal family issues. As a result, the time and energy needed to focus on my studies with Launch School quickly dwindled, and by December, I had more or less put my studies on the back burner.</p><p>For the time being the road to becoming a software developer was put on hold, and as far as I knew it was put on hold indefinitely.</p><h2 id="the-road-to-software-engineering">The Road to Software Engineering</h2><p>For the previous decade I had been (and still am) a residential real estate broker, helping people buy and sell real estate all over the metropolitan area where I live. For most of that time I’ve also been <em>the</em> broker, meaning that I operate under my own license and firm. In more pedestrian terms, it simply means that I'm the boss— which, of course, is not quite as glamorous as it sounds, as I also own every other job title that goes with operating a business like this. If there’s a task to be done, in most cases I'm the one doing it.</p><p>For the most part helping people buy and sell real estate has been a solid career. It’s provided a good income while giving me the opportunity to run my own business, and much of the work involves guiding people through what is often one of the most stressful and financially significant events of their lives. Being able to help people navigate such a momentous time in their lives can be incredibly rewarding, especially when it involves donning the dual roles of successful negotiator and quasi-therapist, as the job often requires calming the nerves of clients who typically buy or sell a home only a few times over the course of their entire lives.</p><p>And yet for all of the benefits my career in real estate had provided, something had always been missing.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://images.unsplash.com/photo-1499428665502-503f6c608263?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDIwfHxhbG9uZSUyMGJsYWNrJTIwYW5kJTIwd2hpdGV8ZW58MHx8fHwxNjU5NDAzMDE5&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" class="kg-image" alt="Finding My Way Back to Launch School" loading="lazy" width="2400" height="1600" srcset="https://images.unsplash.com/photo-1499428665502-503f6c608263?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDIwfHxhbG9uZSUyMGJsYWNrJTIwYW5kJTIwd2hpdGV8ZW58MHx8fHwxNjU5NDAzMDE5&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=600 600w, https://images.unsplash.com/photo-1499428665502-503f6c608263?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDIwfHxhbG9uZSUyMGJsYWNrJTIwYW5kJTIwd2hpdGV8ZW58MHx8fHwxNjU5NDAzMDE5&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1000 1000w, https://images.unsplash.com/photo-1499428665502-503f6c608263?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDIwfHxhbG9uZSUyMGJsYWNrJTIwYW5kJTIwd2hpdGV8ZW58MHx8fHwxNjU5NDAzMDE5&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1600 1600w, https://images.unsplash.com/photo-1499428665502-503f6c608263?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDIwfHxhbG9uZSUyMGJsYWNrJTIwYW5kJTIwd2hpdGV8ZW58MHx8fHwxNjU5NDAzMDE5&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2400 2400w" sizes="(min-width: 720px) 720px"><figcaption>Photo by <a href="https://unsplash.com/@bigkids?utm_source=ghost&utm_medium=referral&utm_campaign=api-credit">David Werbrouck</a> / <a href="https://unsplash.com/?utm_source=ghost&utm_medium=referral&utm_campaign=api-credit">Unsplash</a></figcaption></img></figure><p>For as long as I can remember I've consistently loved doing two things— building stuff and solving problems. While my role as a real estate broker requires a fair amount of creative problem solving — negotiating deals and working through the inevitable challenges that real estate transactions bring — it tends to be the same problems requiring the same solutions over and over again. Don't get me wrong; meeting people, building relationships with them and helping them achieve a goal with so much at stake is a great way to spend a career. But solving the same problems over and over again can leave a mind that needs to be constantly challenged living in a perpetual state of dissatisfaction and longing for that next 'interesting' thing.</p><p>To put it bluntly, I was often bored with the core tasks involved with performing my job. Couple that with consistently working nights and weekends (often unpredictably) and the constant need to find new clients (which I've never liked), and you've got a recipe for an unfulfilling career. As a result, I was feeling as though I had hit a plateau and started to seriously think about whether or not there might be a viable path to making a near mid-life career change.</p><p>A path to a career in software engineering almost seemed inevitable. I've always had a deep interest in technology, even from childhood, whether obsessing over my first Nintendo gaming system or entering a command on an Apple IIe for the first time. A perpetual tinkerer, I was always fascinated by the underlying mechanics of how things worked.</p><p>Like many people, I had assumed that a career in software engineering started with a 4-year degree in a related field; and that if you didn't start there, you missed your chance unless you wanted to enroll in a program to get that degree. For me, I had studied philosophy and classical languages and literature, and by the time I had gotten curious about a career in software engineering, enrolling in a university program again did not sound appealing at all.</p><p>So what, then, does one do?</p><p>A few years back I had met a software engineer named Jeff. We were actually co-workers when I took a short gig as the Director of Sales for a real estate tech startup. Unlike the other engineers, Jeff didn't have any experience as a software engineer before joining the team; he didn't even have a degree in a related field. What he did have, though, was a certificate from a software engineering bootcamp.</p><p>Until then I had never heard of such a thing— an intensive program where within just a few months you could ostensibly learn what you need to know to start a career as a software engineer. It was an interesting datapoint at the time, and just that — a datapoint — as I wasn't quite ready then to broach the idea of switching my career into a different industry, to a position completely unrelated to anything I had ever done before. But the idea would stick with me— an idea that I would revisit again a few years later.</p><p>By early to mid 2020, I was ready to make that change I had been thinking about, even itching for. Remembering my former colleague, Jeff, who had leveraged a bootcamp to start a career as a software engineer, I started researching everything I could about bootcamps— course offerings, program duration, tuition, job outcomes, online reviews... literally everything I could get my hands on.</p><p>It was <em>really</em> enticing— the idea that I could invest just a few months to completely take my career into a new direction. But was it really possible, becoming a software engineer in just a few months time? Every bootcamp certainly said I could, with most waving around self-published reports showing statistics of 80-90% job placement within 6 months to a year of completing their programs. There was also a lot of polished marketing promising the prize of a new job in tech, while brandishing the logos of all the companies their graduates were working at.</p><p>It all sounded promising on paper. But as I continued to research the idea of attending a bootcamp to make a career change, and as I even started to narrow down potential choices, I never had a feeling of complete confidence that a bootcamp would be the right choice for me. While I attended several consultations and Q&amp;A events with different bootcamps, I never left feeling like my questions were adequately answered or that even attending <em>their</em> bootcamp would be the right choice for me. And for all of the fancy marketing, for all the promises of how just a few months of study was all I needed to become a software engineer, and for all the self-reported "statistics" for job placement, none of it ever closed the "trust gap" for me. And if I couldn't totally trust a bootcamp with my future career, I certainly wasn't going to commit a sizable portion of my future salary to them either.</p><h2 id="discovering-launch-school">Discovering Launch School</h2><p>I really wrestled with whether or not to attend a bootcamp. I badly wanted to get into software engineering, but the allure of bootcamp promises reeked just a bit too much of snake oil for my taste. And that cloud of distrust made me a bit nervous to take the bootcamp plunge.</p><p>Then one day it happened— some random person, in some random Twitter discussion about software engineering bootcamps, told some other random person that they should check out <a href="http://launchschool.com">Launch School</a>.</p><p>"Launch School...?" I thought.</p><p>I had never heard of Launch School, even though I felt like I had researched bootcamps to the high heavens and knew all the viable options out there. Still heavily in the research phase of things, off to Google I went...</p><p><em>Whoa</em>...</p><p>One of the first things that stands out after a quick visit to Launch School's website: while you can digest what a bootcamp has to offer in about 20 minutes or less of perusing its website, it takes at least <em>a few hours</em> to fully digest everything at Launch School's website and really understand all it has to offer, from program goals, to its mastery-based approach to pedagogy, to what it really takes to launch a career in software engineering, to outcomes, etc. And while dense and lengthy (especially reading it's approach to mastery-based learning), having so much information available about the program was a massive breath of fresh air. What I really wanted was information, because how can one make a critical decision without sufficient information upon which to make that decision?</p><p>With bootcamps, I felt like the only thing I had to base a career-changing decision on was mostly lots of marketing material and self-reported outcomes that were fuzzy at best or deceptive at worst if you really studied the reports. There were student reviews at places like <a href="https://www.coursereport.com">Course Report</a>, but if you look closely, a large portion of those reviews are from current students early in their programs, not ones who actually finished and got a job they were happy with. But with Launch School, I felt it really laid everything out on the table. There was just so much information available to anyone willing to invest the time to review it— its informative website, lots of student-written articles on Launch School's excellent <a href="https://medium.com/launch-school">Medium publication</a>, interviews with current and former students on its <a href="https://podcast.launchschool.com">podcast</a>, and, of course, a plethora of glowing reviews on <a href="https://www.coursereport.com/schools/launch-school#reviews" rel="noopener">Course Report</a> . With so much information available, especially from students past and present, I felt I had enough information to make a truly informed decision.</p><p>Obviously traditional bootcamps work for some people — probably even a lot of people, depending on what your goals and expectations are. But for me, making a decision to attend a bootcamp felt more like a leap of faith than a calculated decision. And that bar just isn't high enough when there's a career and tens of thousands of dollars in educational costs on the line. By contrast, decisions of this nature need to be very, <em>very</em> calculated.</p><p>In short, Launch School closed the "trust gap" for me, which no other program was able to do. Nearly devoid of any marketing fluff, the approach wasn't to get as many students through the door as possible. Rather, Launch School presented itself as the right solution <em>only if my goals aligned with the goals of the program</em>— mastery over awareness, fundamental engineering principles over the trending framework of the moment, launching a career over just getting a job, taking the slow and studious path as the means to better long-term career prospects. It all really resonated with me, as I've never been one to take the shortest route if an exponentially better route lay ahead, even if that route were a little bit longer. In fact, it didn't just resonate with me; it was all leading to a very calculated decision based on the plethora of information available to prospective students, from the mastery-based pedagogy, to student articles and interviews, to the industry-leading salaries coming out of its <a href="https://launchschool.com/capstone">Capstone</a> program. Plus, at just $199/mo (at the time of writing) and no commitment for the Core Curriculum, there was virtually no risk.</p><p>So in September 2020, I started Launch School's free prep course.</p><h2 id="rediscovering-focus-through-launch-school">Rediscovering Focus through Launch School</h2><p>I finished Launch School's prep course mid-October 2020, and promptly enrolled in its Core Curriculum the same day. That effort swiftly died around December 2020 for the reasons mentioned above, and the next time I would invest serious time and effort into Launch School's program would be mid-July 2021.</p><p>And I am <em>so</em> glad I found my way back.</p><p>Ramping up and getting fully into the swing of studying again took about 6 weeks. Because I had taken about 7 months off, I had to go back and review everything I had learned before— a bit of a drag but a necessary step in getting back on track. Launch School is about <em>mastery</em> after all, not just getting by. In fact, there is no such thing as good enough at Launch School; you can't even move from one course to the next without passing one or two assessments <em>per course</em> with very high scores. Even when you do pass with high scores, you are still asked to go back and refine answers that while technically acceptable could still benefit from improvement.</p><p>By early September I had hit a stride of serious daily study and was once again making real progress. By the third week of September I had completed the first course, RB101, and by October 7th (my birthday!) I had passed the written assessment for that same course. Two weeks later I would pass the interview assessment, culminating in the completion and passing of my first Launch School course.</p><p>It felt <em>amazing</em>.</p><p>Learning software engineering is tough; we all know that. But the depth through which Launch School's curriculum takes you is especially difficult. Coupled with Launch School's very high standards, where conceptual fuzziness isn't allowed and the standard for excellence is <em>mastery</em>, passing assessments is a monumental achievement even for the best of us. This is especially true when you invest so much time and effort into not just knowing but <em>mastering</em> the course material. Best of all, because of Launch School's strict, high standards, when you pass an assessment you can rest assured that you truly have mastered the material at a high level.</p><p>At the time of writing, I am just on the verge of taking the assessment for my third Launch School course (there are 12 courses total in the Core Curriculum— 22 if you count the assessments). And what a ride it's been. Learning the course material, studying for the assessments and then subsequently passing the assessments has been one of the most rigorous academic experiences I've ever had; and this is coming from someone who studied philosophy and Greek and Latin in both college and graduate school. Some of that challenge no doubt comes from learning difficult material I've never studied before, but it also comes from the rigor of the Launch School curriculum and the high standards imposed on students for moving through the coursework.</p><p>As difficult and challenging as this path has been so far, I have a deep gratitude for it all. Even though the Core Curriculum is self-paced, with no live classroom instruction and no cohorts (the opposite is true of the Capstone program, of which the Core Curriculum is a prerequisite), I've been immersed in an amazing community of studious, focused learners, where the pursuit of mastery is a given, not an afterthought. And that feeling of mastery, coupled with the endpoint of the excellent career outcomes Launch School is known for, has given me a level of focus and excitement for my career I can't say I've ever had until now.</p><p>Without Launch School, I probably wouldn't be on this path to a new career in software engineering. Even with the plethora of bootcamps out there, it seems likely that I would never have felt confident enough to go down that route, with the high cost, the inability to leave once you start and the lack of confidence about the outcome once I finished. Especially with the significantly lower average salaries compared to Launch School's Capstone program, enrolling in a traditional bootcamp was even less appealing.</p><p>So thank you, Launch School, for helping me regain focus and excitement for my career, and for giving me what is likely the only viable opportunity I would have had to make the career change I so badly wanted... and probably even needed.</p><p>Onward and upward....</p>]]></content:encoded></item><item><title><![CDATA[Class and Interface Inheritance in Ruby]]></title><description><![CDATA[Inheritance in object oriented programming is a concept that refers to the ability of classes to inherit behaviors from other classes. It is not, however, a two-way inheritance. In other words, one class, a subclass, inherits behaviors from another class, a superclass; the superclass does not inherit behaviors from the subclass.


In Ruby there are two types of inheritance: class inheritance and interface inheritance. Both are equally important and together widen our ability to give functionalit]]></description><link>https://wayneo.co/class-and-interface-inheritance-in-ruby/</link><guid isPermaLink="false">Ghost__Post__62e9d4bbf3103934aeef36b5</guid><category><![CDATA[Software Development]]></category><category><![CDATA[Ruby]]></category><dc:creator><![CDATA[Wayne Olson]]></dc:creator><pubDate>Tue, 07 Dec 2021 02:04:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1472173148041-00294f0814a2?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDV8fGluaGVyaXRhbmNlfGVufDB8fHx8MTY1OTQwMjMxMQ&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://images.unsplash.com/photo-1472173148041-00294f0814a2?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxMTc3M3wwfDF8c2VhcmNofDV8fGluaGVyaXRhbmNlfGVufDB8fHx8MTY1OTQwMjMxMQ&ixlib=rb-1.2.1&q=80&w=2000" alt="Class and Interface Inheritance in Ruby"/><p>Inheritance in object oriented programming is a concept that refers to the ability of classes to inherit behaviors from other classes. It is not, however, a two-way inheritance. In other words, one class, a <strong>subclass</strong>, inherits behaviors from another class, a <strong>superclass</strong>; the superclass does not inherit behaviors from the subclass.</p>
<p>In Ruby there are two types of inheritance: <strong>class</strong> <strong>inheritance</strong> and <strong>interface inheritance</strong>. Both are equally important and together widen our ability to give functionality to objects while adding the benefits of simplicity, flexibility and scalability to our code.</p>
<h2 id="class-inheritance">Class Inheritance</h2>
<p>Class inheritance is created when common behaviors (methods) are extracted to a superclass from which one or more subclasses inherit those behaviors. This means that an object of the subclass can invoke methods that are defined in the superclass without the method needing to be defined in the subclass. We can think of a superclass as a library of methods that, when inherited, extends the functionality of the subclass; in other words, a subclass has not only the functionality defined within itself but the functionality of its superclass as well. The syntax to indicate class inheritance is simple: when defining a class we use the <code>&lt;</code> character after the class name, followed by the name of the superclass.</p>
<p>For example, let's say we have a restaurant where we want to define an <code>Employee</code> superclass with multiple subclasses of different types of employees. Here is how we would indicate that a class <code>Host</code> is a subclass of the superclass <code>Employee</code>:</p>
<pre><code class="language-ruby">class Employee
  def clock_in
    &quot;I clocked in!&quot;
  end
end

class Host &lt; Employee; end
</code></pre>
<p>To see how inheritance is implemented in the code above, we can simply invoke the <code>clocked_in</code> method from the <code>Employee</code> class on an object of the <code>Host</code> class.</p>
<pre><code class="language-ruby">class Employee
  def clock_in
    &quot;I clocked in!&quot;
  end
end

class Host &lt; Employee; end

host = Host.new

puts host.clock_in
# =&gt; &quot;I clocked in!&quot;
</code></pre>
<p>To further demonstrate the implementation and benefits of inheritance we can add some complexity to our example.</p>
<pre><code class="language-ruby">class Employee
  def clock_in
    &quot;I clocked in!&quot;
  end

  def clock_out
    &quot;I clocked out!&quot;
  end
end

class Host &lt; Employee; end

class Server &lt; Employee; end

class Busser &lt; Employee; end

class Cook &lt; Employee; end

host = Host.new
puts host.clock_in
# =&gt; &quot;I clocked in!&quot;
puts host.clock_out
# =&gt; &quot;I clocked out!&quot;

server = Server.new
puts server.clock_in
# =&gt; &quot;I clocked in!&quot;
puts server.clock_out
# =&gt; &quot;I clocked out!&quot;

busser = Busser.new
puts busser.clock_in
# =&gt; &quot;I clocked in!&quot;
puts busser.clock_out
# =&gt; &quot;I clocked out!&quot;

cook = Cook.new
puts cook.clock_in
# =&gt; &quot;I clocked in!&quot;
puts cook.clock_out
# =&gt; &quot;I clocked out!&quot;
</code></pre>
<p>As mentioned previously, inheritance allows us to extract common behaviors to a single superclass. This means that we can write code once and then reuse that same code in as many subclasses as needed, all without having to rewrite the same code over and over again. We see this in the above code with the <code>clock_in</code>  and <code>clock_out</code> methods from the <code>Employee</code> superclass: we've defined the methods once and can invoke them from any of the subclasses we've defined after it. Without inheritance we would have to define the <code>clock_in</code> and <code>clock_out</code> methods in every class where those behaviors are needed.</p>
<p>Additionally, with inheritance we can still define more fine-tuned behaviors in a subclass that may not be applicable to all subclasses of the superclass from which the subclass inherits. To further elaborate on our example above, while every employee has the ability to clock in and clock out when starting and ending a shift, each employee also has behaviors specific to the employee’s role. For example, while a server can serve guests, a host cannot.</p>
<pre><code class="language-ruby">class Employee
  def clock_in
    &quot;I clocked in!&quot;
  end

  def clock_out
    &quot;I clocked out!&quot;
  end
end

class Host &lt; Employee
  def seat_guest
    &quot;Guest has been seated.&quot;
  end
end

class Server &lt; Employee
  def serve_guest
    &quot;Guest has been served.&quot;
  end
end

class Busser &lt; Employee
  def bus_table
    &quot;Table has been cleared.&quot;
  end
end

class Cook &lt; Employee
  def cook_dish
    &quot;Dish has been cooked.&quot;
  end
end
</code></pre>
<p>Structuring code in classes that inherit behaviors from a common superclass enables great flexibility in the code we write. With such flexibility we can easily reuse the common behaviors that we’ve extracted into superclasses while still defining more specific behaviors in subclasses where needed. For example, we can define as many subclasses of the <code>Employee</code> class as needed  — executives, managers, marketers, dishwashers and so on — without having to rewrite and repeat any of the behaviors inherited from the <code>Employee</code> superclass.</p>
<p>But what if we have common behaviors shared between multiple but not all subclasses? For example, let’s say that servers are able to perform the same functions that a host does— taking down the guest’s name, seating the guest and giving the guest a menu. Does this mean that we need to define all of these behaviors in both classes? Or is there a way to extract those behaviors to common, inheritable location as well?</p>
<p>The second type of inheritance — <em>interface</em> inheritance — allows us to do just that.</p>
<h2 id="interface-inheritance">Interface Inheritance</h2>
<p>Before we dive into a discussion of interface inheritance, let’s continue our thought experiment with our make-believe restaurant. To do so, let’s postulate that an object of a <code>Server</code> class is able to perform many of the same functions as an object of the <code>Host</code> class, specifically functions related to seating a guest. For example, both hosts and servers are able to take down a guest's name, seat the guest at a table, give the guest a menu and inform the guest of the daily special when the guest is seated. However, because these are not behaviors that are shared among all subclasses of the <code>Employee</code> superclass, we do not want these behaviors to be defined in that class and then inherited by subclasses for whom those behaviors would not be appropriate (like cooks and bussers).</p>
<p>Let’s modify our code to give our <code>Host</code> and <code>Server</code> classes these new behaviors.</p>
<pre><code class="language-ruby">class Employee
  def clock_in
    &quot;I clocked in!&quot;
  end

  def clock_out
    &quot;I clocked out!&quot;
  end
end

class Host &lt; Employee
  def take_guest_name
    # implementation
  end

  def seat_guest
    # implementation
  end

  def give_guest_menu
    # implementation
  end

  def recite_daily_special
    # implementation
  end
end

class Server &lt; Employee
  def take_guest_name
    # implementation
  end

  def seat_guest
    # implementation
  end

  def give_guest_menu
    # implementation
  end

  def recite_daily_special
    # implementation
  end

  def serve_guest
    &quot;Guest has been served.&quot;
  end
end

class Busser &lt; Employee
  def bus_table
    &quot;Table has been cleared.&quot;
  end
end

class Cook &lt; Employee
  def cook_dish
    &quot;Dish has been cooked.&quot;
  end
end
</code></pre>
<p>That’s <em>a lot</em> of repetitive code, which leads us to ask: is there a way to extract that code to a common location, from which the <code>Host</code> and <code>Server</code> classes can inherit those behaviors in the way we did with class inheritance from the <code>Employee</code> class? <em>Interface</em> inheritance enables us to do just that. The difference though is that, rather than inheriting the behaviors from a superclass, these behaviors can be inherited from a <em>module</em>.</p>
<p>A module is similar to a class in that it is a collection of related behaviors; however, a key difference is that an object <em>cannot</em> be instantiated from a module. While a class provides a blueprint for the state and behaviors of objects instantiated from the class, a module simply adds functionality to a class where that module has been included. As a collection of behaviors, a module can be “mixed in&quot; to a class by invoking the <code>include</code> method, followed by the name of the module. When a module is used this way it is called, appropriately, a <em>mixin module</em>. Modules are defined like classes except by using the <code>module</code> keyword instead.</p>
<p>Let’s go back to our example above and extract the methods common to both the <code>Host</code> and <code>Server</code> classes to a module called <code>Hostable</code> <sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>.</p>
<pre><code class="language-ruby">module Hostable
  def take_guest_name
    # implementation
    puts 'Guest name taken...'
  end

  def seat_guest
    # implementation
    puts 'Guest seated...'
  end

  def give_guest_menu
    # implementation
    puts 'Menu given to guest...'
  end

  def recite_daily_special
    # implementation
    puts 'Daily special recited...'
  end
end

class Employee
  def clock_in
    &quot;I clocked in!&quot;
  end

  def clock_out
    &quot;I clocked out!&quot;
  end
end

class Host &lt; Employee
  include Hostable
end

class Server &lt; Employee
  include Hostable

  def serve_guest
    &quot;Guest has been served.&quot;
  end
end

class Busser &lt; Employee
  def bus_table
    &quot;Table has been cleared.&quot;
  end
end

class Cook &lt; Employee
  def cook_dish
    &quot;Dish has been cooked.&quot;
  end
end

host = Host.new
host.seat_guest
# =&gt; 'Guest seated...'

server = Server.new
server.seat_guest
# =&gt; 'Guest seated...'
</code></pre>
<p>As you can see in our example above, we’ve deduplicated all of the functionality related to seating a guest and extracted it to a single module named <code>Hostable</code> . We then gave access to that functionality in our <code>Host</code> and <code>Server</code> classes by mixing in the <code>Hostable</code> module via invocation of the <code>include</code> method. In fact, we can include as many modules as may be appropriate for the class in question. For example, let's say that both hosts and servers, but not bussers and cooks, can sing a birthday song when a guest visits the restaurant on her birthday. Rather than writing a <code>sing_birthday_song</code> method in both the <code>Host</code> and <code>Server</code> classes, we can define that method in a <code>Singable</code> module and then include that module in the two classes, just as we did with the <code>Hostable</code> module.</p>
<pre><code class="language-ruby">module Hostable
  # code omitted for brevity
end

module Singable
  def sing_birthday_song
    # implementation
  end
end

class Employee
  def clock_in
    &quot;I clocked in!&quot;
  end

  def clock_out
    &quot;I clocked out!&quot;
  end
end

class Host &lt; Employee
  include Hostable
  include Singable
end

class Server &lt; Employee
  include Hostable
  include Singable

  def serve_guest
    &quot;Guest has been served.&quot;
  end
end
</code></pre>
<p>Structuring inheritance through modules gives Ruby classes the ability to inherit from multiple places. While some programming languages have multiple inheritance, which means that a subclass can inherit from more than one superclass, Ruby is strictly a <em>single inheritance</em> language. However, through the use of modules and interface inheritance, Ruby can mimic multiple inheritance.</p>
<h2 id="class-inheritance-vs-interface-inheritance">Class Inheritance vs. Interface Inheritance</h2>
<p>So far we have seen both class and interface inheritance in practical examples, but it may not yet be clear as to when one might use one or the other to structure behaviors and the classes that inherit them.</p>
<p>You’ll recall from earlier in our discussion that inheritance is about grouping common behaviors into a single place from which multiple classes can inherit these behaviors, with that single place being either a superclass or a module. In both cases, the goal is to group common behaviors that can be defined once and then reused as many times as needed without duplicating code unnecessarily. Yet we want to group behaviors in such a way that the behaviors being inherited are appropriate to the classes that inherit them. In doing so, we can write code that is more flexible, highly scalable and much easier to maintain.</p>
<p>In general, if there is a ‘is-a’ relationship between classes, class inheritance is typically the best place to start. Class inheritance allows us to structure classes and behaviors into logical hierarchies, often in a way that models the hierarchies we see in the real world. Referring back to the examples we used previously, a host ‘is a’ employee, as is a server, a busser and a cook. And, naturally, as members of a more general class of <code>Employee</code> , there will be behaviors that each of them have in common, such as clocking in and out at the start and end of a shift.</p>
<p>However, there are often exceptions to this sort of hierarchical modeling such that there may be behaviors that <em>some</em> subclasses have in common but not all. We saw this with the <code>Host</code> and <code>Server</code> classes, which were both able to perform the functions of a host (i.e., seating guests). Since such behaviors are common only to them and not the other subclasses of the <code>Employee</code> superclass, we should not define these behaviors in the <code>Employee</code> class, since this would result in subclasses (like bussers and cooks) inheriting behaviors which would not be appropriate for them to have.</p>
<p>The alternative of course is to define these methods in the individual subclasses that need them; but that’s not a very good alternative, as our code becomes unnecessarily repetitive. This is where interface inheritance through mixin modules comes in. When common behaviors don’t necessarily fit into the hierarchical models we’ve created through subclassing, and there is a ‘has-a’ relationship between these behaviors and the classes that need them, then interface inheritance would typically be the better choice in such a case. This is exactly what we saw with the <code>Host</code> and <code>Server</code> classes and the <code>Hostable</code> module, where the behaviors didn't fit into the <code>Employee</code> superclass, and both the <code>Host</code> and <code>Server</code> classes &quot;had” the behaviors in the <code>Hostable</code> module.</p>
<h2 id="chain-of-inheritance-and-the-method-lookup-path">Chain of Inheritance and the Method Lookup Path</h2>
<p>Even though Ruby is a language of single inheritance, where a class can have only one superclass, it is the case that a class also inherits the behaviors that its superclass inherits. That’s a bit of a mouthful, but it simply means that there is always a chain of inheritance involved when subclassing one class from another. Like water running from the top to the bottom of a chain, the water (behaviors) runs through any links (classes) in the chain that are created through subclassing additional classes until it reaches the last link in the sequence.</p>
<p>For our restaurant thought experiment we created an <code>Employee</code> superclass with a number of employee type subclasses. To demonstrate this chain of inheritance, we're now going to define a <code>Person</code> superclass from which the <code>Employee</code> class subclasses. Additionally, we will also create a class <code>Guest</code> , which also subclasses from the <code>Person</code> class, in addition to <code>Adult</code> and <code>Child</code> classes that subclass from <code>Guest</code> .</p>
<pre><code class="language-ruby">class Person
  attr_reader :name

  def initialize(name)
    @name = name
  end
end

# classes related to a Guest
class Guest &lt; Person; end

class Adult &lt; Guest; end

class Child &lt; Guest; end

# classes related to an Employee
class Employee &lt; Person; end

class Host &lt; Employee; end

class Server &lt; Employee; end

class Busser &lt; Employee; end

class Cook &lt; Employee; end
</code></pre>
<p>To make it easier to see, let’s extract the structure we’ve created between our classes.</p>
<pre><code class="language-plaintext">Person &lt; Guest &lt; Adult
Person &lt; Guest &lt; Child
Person &lt; Employee &lt; Host
Person &lt; Employee &lt; Server
Person &lt; Employee &lt; Busser
Person &lt; Employee &lt; Cook
</code></pre>
<p>With this structure in place, the final subclasses in the chain we’ve created inherit behaviors that are defined at the top of the chain as well as any classes in between. For example, the <code>Host</code> class inherits the behaviors in the <code>Person</code> class because these behaviors are inherited in the <code>Employee</code> class, and the <code>Host</code> class inherits behaviors from the <code>Employee</code> class.</p>
<p>To see this chain of inheritance in practice we’ll create an object from the <code>Adult</code> class and then invoke the <code>name</code> method that's defined in the <code>Person</code> class.</p>
<pre><code class="language-ruby">class Person
  attr_reader :name

  def initialize(name)
    @name = name
  end
end

# classes related to a Guest
class Guest &lt; Person; end

class Adult &lt; Guest; end

class Child &lt; Guest; end

# classes related to an Employee
class Employee &lt; Person; end

class Host &lt; Employee; end

class Server &lt; Employee; end

class Busser &lt; Employee; end

class Cook &lt; Employee; end

adult = Adult.new('Nancy')
puts adult.name
# =&gt; 'Nancy'
</code></pre>
<p>As we saw in our discussion of class inheritance, we are able to invoke the <code>name</code> method that's defined in the <code>Person</code> class on an object of the <code>Adult</code> class, even though the <code>name</code> method is defined in neither the <code>Adult</code> class nor in the <code>Guest</code> class. This, again, is inheritance at work.</p>
<p>To illustrate the chain of inheritance further, consider the commonly used <code>object_id</code> method. This method can be invoked on any Ruby object, even though this method isn't defined in any of the classes of the objects upon which we commonly invoke this method (e.g., strings, integers and arrays). This is because the <code>object_id</code> method is an instance method of the <code>Object</code> class, and all Ruby objects ultimately inherit from the <code>Object</code> class in the chain of inheritance.</p>
<p>For example, if we were to invoke the <code>object_id</code> method on an object of the <code>Cook</code> class, the chain of inheritance would look like this:</p>
<pre><code class="language-plaintext">Object &lt; Person &lt; Employee &lt; Cook
</code></pre>
<p>In Ruby there is a specific mechanism underlying this chain of inheritance called the <strong>method lookup path</strong>. This is the means by which Ruby locates a method definition in order to execute a method invocation of the same name. In more pedestrian terms, this is the answer to the question: how does Ruby know where to find the definition of a method when it's invoked? We can think of the method lookup path exactly as the name implies: the path that Ruby takes through the chain of inheritance to find a method definition for an invoked method.</p>
<p>For any method invocation, the general sequence that Ruby follows to find a matching method definition looks like this:</p>
<pre><code class="language-plaintext">Class (of the object upon which the method was invoked)
  ↓
Module(s)
  ↓
Superclass
  ↓
[repeat w/the Superclass now in the beginning position taken by Class]
</code></pre>
<p>As you can see in the outline above, Ruby first looks in the class of the object upon which the method was invoked. If Ruby doesn’t find a matching method definition there, Ruby then looks in included modules, if any. If there are two or more modules included in the class, Ruby looks in the most recently included module first (which would be the last included module), then works its way backwards through any remaining modules. If a method definition still hasn’t been found, Ruby then looks in the class’s superclass, repeating the same cycle as many times as necessary. Once Ruby has exhausted all custom classes and modules without finding a matching method definition, then Ruby continues through the following classes and modules:</p>
<pre><code class="language-plaintext">Object
  ↓
Kernel (module in the Object class)
  ↓
BasicObject
</code></pre>
<p>If Ruby is unable to find a matching method definition anywhere in the method lookup path, a <code>NoMethodError</code> is raised.</p>
<p>To see the method lookup path in practice, let’s consider the following code.</p>
<pre><code class="language-ruby">module Hostable
  def take_guest_name
    # implementation
    puts 'Guest name taken...'
  end

  def seat_guest
    # implementation
    puts 'Guest seated...'
  end

  def give_guest_menu
    # implementation
    puts 'Menu given to guest...'
  end

  def recite_daily_special
    # implementation
    puts 'Daily special recited...'
  end
end

module Singable
  def sing_birthday_song
    # implementation
  end
end

class Person
  attr_reader :name

  def initialize(name)
    @name = name
  end
end

class Employee &lt; Person
  def clock_in
    &quot;I clocked in!&quot;
  end

  def clock_out
    &quot;I clocked out!&quot;
  end
end

class Host &lt; Employee
  include Hostable
  include Singable
end

class Server &lt; Employee
  include Hostable
  include Singable

  def serve_guest
    &quot;Guest has been served.&quot;
  end
end

class Busser &lt; Employee
  def bus_table
    &quot;Table has been cleared.&quot;
  end
end

class Cook &lt; Employee
  def cook_dish
    &quot;Dish has been cooked.&quot;
  end
end

host = Host.new('Dave')
host.seat_guest
# =&gt; 'Guest seated...'

server = Server.new('Betsy')
server.name
# =&gt; 'Betsy'
</code></pre>
<p>In the above example we have created two objects, one of the <code>Host</code> class and one of the <code>Server</code> class. On our <code>host</code> object we have invoked the <code>seat_guest</code> method.</p>
<p>Upon invocation of the <code>seat_guest</code> method on <code>host</code> , here’s the method lookup path that Ruby uses to locate the matching method definition.</p>
<pre><code class="language-plaintext">Host
  ↓
Singable
  ↓
Hostable

[seat_guest method definition found in Hostable module]
</code></pre>
<p>Had a <code>seat_guest</code> method <em>not</em> been found, Ruby would have exhausted the entire method lookup path before raising a <code>NoMethodError</code>.</p>
<pre><code class="language-plaintext">Host
  ↓
Singable
  ↓
Hostable
  ↓
Employee
  ↓
Person
  ↓
Object
  ↓
Kernel
  ↓
BasicObject
  ↓
[NoMethodError]
</code></pre>
<h2 id="conclusion">Conclusion</h2>
<p>To summarize, inheritance refers to the ability of one class to inherit the behaviors of another class, which allows us to extract common code to a single inheritable location. Because Ruby is a single inheritance language, which means that a class can only subclass from a single superclass, Ruby has two types of inheritance: class inheritance and interface inheritance. While class inheritance allows us to create hierarchical relationships between classes, it doesn’t always make sense for certain behaviors that are shared between only some subclasses to be inherited from the superclass. As a result, interface inheritance through mixin modules gives us the ability to mimic multiple inheritance. To execute a method invocation, Ruby uses the method lookup path to find the matching method definition.</p>
<p>—</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>The common naming convention for mixin modules is to append the ‘-able’ suffix to the module name. <a href="#fnref1" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown--></hr>]]></content:encoded></item><item><title><![CDATA[A Mental Model for Understanding Encapsulation in Ruby]]></title><description><![CDATA[A discussion of encapsulation, how it is implemented in Ruby, and how exactly it benefits the code we write on a practical level.]]></description><link>https://wayneo.co/a-mental-model-for-understanding-encapsulation-in-ruby/</link><guid isPermaLink="false">Ghost__Post__62e9d4bbf3103934aeef36b4</guid><category><![CDATA[Software Development]]></category><category><![CDATA[Ruby]]></category><dc:creator><![CDATA[Wayne Olson]]></dc:creator><pubDate>Sun, 05 Dec 2021 15:45:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1574043948184-144f2ef80fe3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDJ8fGNhcHN1bGV8ZW58MHx8fHwxNjU4NzYwMjY3&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://images.unsplash.com/photo-1574043948184-144f2ef80fe3?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxMTc3M3wwfDF8c2VhcmNofDJ8fGNhcHN1bGV8ZW58MHx8fHwxNjU4NzYwMjY3&ixlib=rb-1.2.1&q=80&w=2000" alt="A Mental Model for Understanding Encapsulation in Ruby"/><p>Encapsulation in object oriented programming is the grouping of data into objects while making that data unavailable to other parts of a codebase. It's one of the fundamental conceptual pillars of object oriented programming (along with abstraction, polymorphism and inheritance).</p>
<p>More simply, encapsulation is akin to placing information into a bucket, closing the lid and then hiding that information from the curious and prying eyes of others. Within the context of object oriented programming, the data we're hiding is the attributes that an object has (which together comprise the <em>state</em> of the object) and the functionality (behaviors) of which the object is capable. Therefore, to say that we have encapsulated data is to say that we have hidden the state and behaviors of an object from the rest of the codebase. To say that we are hiding data is to say that we are making that data inaccessible from the rest of the program, which also <em>protects</em> that data from unintentional manipulation.</p>
<p>In this article I discuss what exactly encapsulation looks like, how methods are used to encapsulate data or expose it to the rest of a codebase, and how exactly encapsulation benefits our ability to design complex programs.</p>
<h2 id="the-hidden-nature-of-objects">The Hidden Nature of Objects</h2>
<p>Ruby uses instance variables to track the values associated with an object’s attributes. For example, we may have a <code>Dog</code> class whose objects have the following attributes: name, weight and age. To track these attributes, our <code>Dog</code> class has instance variables of the same name: <code>@name</code> , <code>@weight</code> and <code>@age</code> . Together, these three instance variables comprise the state of objects instantiated from the <code>Dog</code> class.</p>
<p>Let’s consider the following example:</p>
<pre><code class="language-ruby">class Dog
  def initialize(name, weight, age)
    @name = name
    @weight = weight
    @age = age
  end
end

spot = Dog.new('Spot', 12, 4)
p spot
# =&gt; #&lt;Dog:0x000000010d85f198 @name=&quot;Spot&quot;, @weight=12, @age=4&gt;
</code></pre>
<p>Here we have initialized a local variable <code>spot</code> to a new object of the <code>Dog</code> class. The state of this object is represented by the instance variables that we have initialized in <code>lines 3-5</code> , which tell us that the <code>@name</code> of this object is ‘Spot’, that it has a <code>@weight</code> of ‘12' (lbs) and that its <code>@age</code> is ‘4’. Invoking <code>p</code> on <code>line 10</code> returns a human readable representation of the object <code>spot</code>: the class name of our object, an encoding of the object id and, most importantly for this discussion, all of the instance variables that have been initialized within that object along with their values.</p>
<p>At their most basic level, objects are distinct entities that are separate and independent of each other. We could also say that the internal representation of objects is hidden from each other, where one object is unable to access information about the other. Practically, this means that we cannot interact with an object <em>unless we explicitly expose the state and behaviors of that object to other parts of our code</em>. Ruby uses methods to expose the state of an object, but without these methods an object remains what is essentially an information silo, closed off and isolated from the rest of the world (or, rather, code). <em>With</em> these methods, we can retrieve and manipulate the data within an object.</p>
<p>To use the example above, our dog <code>spot</code> has a number of attributes. However, with the code as currently written there is no way to access them from the rest of the program. To demonstrate this we can attempt to reference one of the instance variables from outside of the class <code>Dog</code> where the instance variable was initialized.</p>
<pre><code class="language-ruby">class Dog
  def initialize(name, weight, age)
    @name = name
    @weight = weight
    @age = age
  end
end

spot = Dog.new('Spot', 12, 4)
p spot
# =&gt; #&lt;Dog:0x000000010d85f198 @name=&quot;Spot&quot;, @weight=12, @age=4&gt;

p @name
# =&gt; nil
</code></pre>
<p>As we saw before, we’ve initialized the <code>@name</code> instance variable in <code>line 3</code>, to which we've assigned the value <code>’Spot’</code> . We also confirmed that the instance variables have been initialized when we invoked <code>p</code> on <code>line 10</code> , which returned the instance variables and their values along with other information about our object <code>spot</code> . Yet when we attempt to reference the variable in <code>line 13</code>, <code>nil</code> is returned.</p>
<p>There’s a good chance this result isn’t surprising to you, but it might not be surprising for the reason you think.</p>
<p>The reason <code>nil</code> is returned when directly referencing the <code>@name</code> instance variable outside of the <code>Dog</code> class is because instance variables are <em>encapsulated</em> in the object where they were initialized. As you recall from the beginning of our discussion, when data is encapsulated it is hidden — that is to say, inaccessible — from other parts of our codebase. For instance variables, they are hidden by default unless we deliberately create a way to access their values. To expose an object's instance variables — to take them out of hiding, so to speak — we have to define methods that allow us to access the instance variable's value outside of the object.</p>
<h2 id="using-methods-to-open-objects-to-the-rest-of-the-world">Using Methods to Open Objects to the Rest of the World</h2>
<p>Instance variables are scoped at the object level, meaning that an instance variable exists only within the object where it was initialized. Therefore, to gain access to the values assigned to an object’s instance variables we have to consider the object as the gateway to access them.</p>
<p>To access these values, we need to define <em>instance</em> <em>methods</em> that expose them to other parts of our code. When an object's instance variables are exposed we can retrieve the values assigned to them, or we can manipulate those values altogether. When we don't have methods that expose them, they remain locked and hidden within the object.</p>
<p>Let’s define instance methods that allow us to retrieve and manipulate the value assigned to one of our instance variables; such methods are called getter and setter methods, respectively. For this example, we’ll use the <code>@name</code> instance variable.</p>
<pre><code class="language-ruby">class Dog
  # previous code omitted for brevity

  def name
    @name
  end

  def name=(new_name)
    @name = new_name
  end
end

spot = Dog.new('Spot', 12, 4)

p spot.name
# =&gt; 'Spot'

spot.name = 'Daisy'

p spot.name
# =&gt; 'Daisy'
</code></pre>
<p>On <code>lines 4-6</code> we've defined our getter method <code>name</code> . When we invoke the <code>name</code> method on <code>line 13</code>, it simply returns the value assigned to the <code>@name</code> instance variable. Likewise, on <code>lines 8-10</code> we've defined our setter method <code>name=()</code> , which reassigns the <code>@name</code> instance variable to the string passed as an argument to the <code>name=()</code> method.</p>
<p>And <em>voilà</em>, we are now able to access the value assigned to <code>@name</code> from outside of the class where it was initialized. With both getter and setter methods in place, we can now both retrieve and reassign the value assigned to <code>@name</code> .</p>
<p>You’ll notice, of course, that the <code>name</code> and <code>name=()</code> instance methods are invoked on our <code>Dog</code> object <code>spot</code>. This is because instance methods can only be invoked on objects of the class where those methods are defined. As mentioned previously, if we want to access information about the state of an object, we have to consider the object as the gateway to that information. If we were to invoke, for example, the <code>name</code> method apart from <code>spot</code> , an error would be raised.</p>
<pre><code class="language-ruby">class Dog
  # previous code omitted for brevity

  def name
    @name
  end

  def name=(new_name)
    @name = new_name
  end
end

spot = Dog.new('Spot', 12, 4)

name
# =&gt; undefined local variable or method `name' for main:Object (NameError)
</code></pre>
<h2 id="controlling-how-objects-are-exposed-with-method-access-control">Controlling How Objects are Exposed with Method Access Control</h2>
<p>Encapsulation allows a programmer to have fine tuned control over what data is hidden within an object and what data is exposed to other parts of a program. Think of it like peeling back the layers of an onion: rather than exposing the entirety of the inner onion, I can peel back as many or as few layers as I want, revealing only as much of the onion as is necessary.</p>
<p>Any discussion of encapsulation necessarily entails a discussion of how exactly Ruby accomplishes the encapsulation of data. Like many other programming languages, Ruby uses the concept of access control to restrict and open access to the methods that allow one to retrieve and manipulate data within an object. Within the context of Ruby, we call this mechanism <em>method access control</em>.</p>
<p>Method access control uses <em>access modifiers</em> to control access to methods. In Ruby, access modifiers are <em>public</em>, <em>private</em> and the less commonly used <em>protected</em>. Public methods are available outside of the class where they are defined, meaning that they can be invoked anywhere without restriction. In Ruby, methods are public unless explicitly declared to be private or protected. In our code example above where we defined getter and setter methods for the <code>@name</code> instance variable, these are public methods since we did not declare them to be otherwise. We also saw this in practice when we successfully invoked the <code>name</code> and <code>name=()</code> methods from outside of the <code>Dog</code> class.</p>
<p>Private methods, on the other hand, can only be invoked from within the class itself. It is also the case that private methods cannot have a caller, because they are implicitly invoked on <code>self</code> .<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup></p>
<p>Let’s look at an example of how to declare a method to be private, as well as the implications of doing so.</p>
<pre><code class="language-ruby">class Dog
  # previous code omitted for brevity

  def name=(new_name)
    @name = new_name
  end

  private  # methods defined after this are private methods

  def name
    @name
  end
end

spot = Dog.new('Spot', 12, 4)

p spot.name
# =&gt; private method `name' called for #&lt;Dog:0x0000000123136608 @name=&quot;Spot&quot;, @weight=12, @age=4&gt; (NoMethodError)
</code></pre>
<p>To declare a method as a private method, we simply include the <code>private</code> method invocation, followed by any method definitions we intend to be private. In the above code, we have taken the <code>name</code> getter method and moved it below the <code>private</code> method invocation. And the result? As we see here, invoking a private method from outside the class raises a <code>NoMethodError</code> as well as an indication that the method we have tried to call is a private method. While Ruby typically raises a <code>NoMethodError</code> when it doesn’t find a method in the calling object's lookup path, in this case it raises the error not because the method doesn't exist but because making the method private has blocked access to it.</p>
<p>As stated previously, private methods can only be invoked from within the class where the method is defined. Now that we’ve declared the <code>name</code> method as a private method, here’s an example of how we can call it without raising an error.</p>
<pre><code class="language-ruby">class Dog
  # previous code omitted for brevity

  def speak
    &quot;My name is #{name}!&quot;
  end

  private

  def name
    @name
  end
end

spot = Dog.new('Spot', 12, 4)

p spot.speak
# =&gt; 'My name is Spot!'
</code></pre>
<p>In <code>line 5</code> we've interpolated the <code>name</code> method within a new method definition, <code>speak</code> , with the resulting output on <code>line 18</code>. Whereas we could not invoke the private <code>name</code> method from outside of the class, this demonstrates that private methods can be invoked by other instance methods of the same class. It also demonstrates how we can <em>encapsulate</em> methods, since private methods are accessible only within the class itself and are protected from invocation outside of the class.</p>
<p>Protected methods lie between public and private methods. Like private methods, they can only be invoked from within the class where they are defined. However, unlike private methods they can be invoked on a calling object other than <code>self</code> , so long as the calling object is an instance of the same class. Protected methods aren't commonly used, but one common use case is when comparing objects of the same class.</p>
<pre><code class="language-ruby">class Dog
  def initialize(name, weight, age)
    @name = name
    @weight = weight
    @age = age
  end

  def &lt;(other)
    weight &lt; other.weight
  end

  protected

  def weight
    @weight
  end
end

spot = Dog.new('Spot', 12, 4)
daisy = Dog.new('Daisy', 25, 12)

puts spot &lt; daisy
# =&gt; true

puts spot.weight
# =&gt; protected method `weight' called for #&lt;Dog:0x00000001260c1710 @name=&quot;Spot&quot;, @weight=12, @age=4&gt; (NoMethodError)
</code></pre>
<p>In the above example we’ve declared <code>weight</code> as a protected method. This allows us to protect the <code>weight</code> method from being accessed outside of the <code>Dog</code> class, while also allowing us to compare the weight of objects of the <code>Dog</code> class as defined in the <code>&lt;</code> method on <code>lines 8-10</code> . Like private methods, protected methods can only be invoked from within the class, but unlike private methods they can be invoked on both <code>self</code> and other objects of the same class.</p>
<h2 id="the-practical-benefits-of-encapsulating-data-in-objects">The Practical Benefits of Encapsulating Data in Objects</h2>
<p>Learning object oriented programming for the first time can be very challenging. Not only is it a major conceptual shift in how we think about programming, but it can be difficult to translate object oriented programming on a conceptual level to how it benefits the code we write on a practical level. This is true as well of understanding encapsulation and how it is implemented in Ruby.</p>
<p>Encapsulating data into objects has two chief benefits:</p>
<ol>
<li>It protects data from unintentional manipulation. In other words, in order to change data within an object there must be obvious intention behind doing so. It also means that we can restrict the way in which data is manipulated.</li>
<li>It allows us to hide complex operations while leaving a simple public interface to interact with those more complex operations.</li>
</ol>
<p>Let’s illustrate these benefits with an example.</p>
<pre><code class="language-ruby">class Person
  attr_accessor :car

  def initialize(name)
    @name = name
    @car = nil
  end
end

class Car
  attr_reader :make, :model, :year, :engine_status

  def initialize(make, model, year)
    @make = make
    @model = model
    @year = year
    @engine_status = :off
  end

  def start_engine
    switch_ignition
    start_relay
    start_motor
    puts &quot;Engine is #{engine_status}!&quot;
  end

  private

  attr_writer :engine_status

  def switch_ignition
    # implementation
    puts 'Starting ignition...'
  end

  def start_relay
    # implementation
    puts 'Starting relay...'
  end

  def start_motor
    # implementation
    puts 'Starting motor...'
    self.engine_status = :on
  end
end

joe = Person.new('Joe')
joe.car = Car.new('Chevy', 'Impala', 1958)

joe.car.start_engine
# =&gt; 'Starting ignition...'
# =&gt; 'Starting relay...'
# =&gt; 'Starting motor...'
# =&gt; 'Engine is on!'

puts joe.car.engine_status
# =&gt; 'on'

joe.car.engine_status = :off
# =&gt; private method `engine_status=' called for #&lt;Car:0x0000000147948bd8 @make=&quot;Chevy&quot;, @model=&quot;Impala&quot;, @year=1958, @engine_status=:on&gt; (NoMethodError)
</code></pre>
<p>The above code illustrates a simple but key point: in order to start the car, the object <code>joe</code> doesn’t need to know the implementation details of every method involved in starting the engine, or even that those methods exist. More specifically, objects of the <code>Person</code> class do not need to access the <code>switch_ignition</code> , <code>start_relay</code>  and <code>start_motor</code> methods, which are all necessary steps in starting an engine. Rather, the only method that objects of the <code>Person</code> class need to know about is the <code>start_engine</code> method; all other implementation details that follow from this method can remain hidden and inaccessible.</p>
<p>And <em>that</em> is encapsulation in practice. We've packaged all of the complex details involved in starting an engine, have made them inaccessible outside of the <code>Car</code> class and instead have defined a simple public interface — the <code>start_engine</code> method — to handle all of the underlying complexity. In fact, this models the real world implementation of starting a car: one doesn’t need to know the internal mechanics of how exactly a car engine starts. Instead, a person only needs to know how to turn the ignition with a key. The rest of the implementation happens under the hood and out of sight; in other words, it is <em>encapsulated</em>.</p>
<p>Notice as well that while we have defined a public getter method for the <code>@engine_status</code> instance variable in <code>line 11</code>, we have made its setter method in <code>line 27</code> private. While we may want the status of the engine to be publicly accessible (for example, a mobile app is able to check if the engine is running), we want only the internal implementation of the object’s class to be able to reassign it, which protects it from the possibility of being directly changed from outside the class. In practical terms, we don't want an object other than a <code>Car</code> to be able to modify <code>@engine_status</code>. Rather, we want it to be changed only as a result of the internal implementation that begins with the public <code>start_engine</code> method and ends with the private <code>start_motor</code> method. In other words, we want the value of <code>@engine_status</code> to reflect the actual status of the engine, while also preventing arbitrary changes that don't. Using method access control to structure our methods this way ensures that <code>@engine_status</code> is manipulated with clear intention and only in the specific way we've designed it to be changed in our program.</p>
<h2 id="conclusion">Conclusion</h2>
<p>In summary, encapsulation allows a programmer to group data into objects and then hide that data from the rest of the codebase. Likewise, it also allows a programmer to expose only data that needs to be accessed outside of the class. By encapsulating data, we can prevent arbitrary changes to data, and we can also hide complex operations while providing a simple public interface to interact with them.</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>As of Ruby 2.7, <code>self</code> can explicitly call private methods. <a href="#fnref1" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown--></hr>]]></content:encoded></item></channel></rss>