Teach Yourself MicroObjects: Output the Data
Encapsulation - it's a huge part of what allows us to be highly effective developers. It's what MicroObjects is about. Encapsulation is the highest thing to strive for when striving to write good code.
If we encapsulate our data so effectively that we can never just access the data... how can we get the data? The basic answer is that you can't. The data is never yours to retrieve from the object.
We return to the most basic question of wanting the data...
Why?
Why do you want the data?
What are you going to do with it?
In the topic today, we're going to display the data - so give it to me!
No.
Displaying data is a behavior. We need to encapsulate that behavior.
If you want to display the data in something, give that thing to object, trust it to display correctly.
That's what today's example is about. How can I write a value to the screen if the object will never give me it's value?
It's a great question. One I solved through some experimentation, and a team I was on didn't see the solution for about 5 months and after I gave some related examples. :)
Like the previous Add Two Ints example, let's go through what changed in the commits.
Output the Data
Along with the initial project set up we create a hard coded test of Console.WriteLine with an int.
Output through Console
One of the big things around encapsulation is how to provide data when it's needed, such as for display, but yet not violate encapsulation by ... well... returning data.
This is the core concept we'll explore in this example.
Provide data without returning data.
Commit
Output Through Implicit Cast
We can output through an implicit cast, but this isn't really what we're going for, just a neat side effect.
Right now, we're adding the MicroObject Primitive for Integer which we'll move onto outputting.
Commit
Wrap Console Write
Part of the process is to create a class that encapsultes the object that needs the raw data.
In this case, we're using Console, so we create a class wrapping the console write functionality. It takes an Integer and will write that out.
We can't test Console - it's external code, 3rd party code. We isolate third party code.
Commit
Integers Write
We need to write without exposing our data. To do this we can use a callback.
It might feel hacky, but it maintains encapsulation. There will be big methods
and strange behavior to get and use data from an object. I've had to implement
a hack and it stands out. If you're doing microObjects, that kinda abuse of the
system is going to be obvious.
Our writer has a method and we pass ourself into it. A lot of the time we'll
turn into text first, so we don't need to overload the IWrite interface, but
that will show up later.
Commit
Moving Writers to Library
File structure is critical with microObjects. Here we've moved the Writers to a nice place
in the Library folder.
Commit
Testing the Integer.Into method
The first test was a visual insepect of the test output window to ensure that the value
was written properly. This test has us passing in a fake that we can inspect the value of
to make sure that what we expected to write was actually written. As this is a method
on the abstract class, all Integers get it for free.
The practice of interface for everything allows us to (almost) always be able to quick and easily generate a fake for our test. In later examples we'll pull in IMock to generate Fake/Mocks quickly and easily for effective and understandable tests.
What to do about duplication?
I could copy and paste more classes from AddTwoInts, and keep duplicating work from
across examples - this isn't an effective way to show one of the bigger concepts,
particularly how microObjects speed up development by having the foundational
components in place. Putting these very basic, code-only classes into a shared library
to build off of will help simplify later projects so we don't need to go through
primitive type extraction every time.
Migrated all primitives to Class Library prj
There's a few reasons the common classes are being extracted into a shared library.
- Avoid having to re-extract the Fluent Types every time
- Avoid a lot of copy and paste
- Demonstrate the power of being able to write new functionality when these simple
pieces already exist - Show the file system in a way that stops being arbitrary.
I hope this helps show microObjects better and doesn't obfuscate.
Summary
That's all the changes to output to the console. I hope this demonstrates how to wrap what needs the raw data in a way that allows the object to never violate encapsulation, and to control all of the behavior around it's data.