update everything, fix up CoP post

This commit is contained in:
Brian Picciano 2020-11-19 22:23:33 -07:00
parent dbf6ebdeee
commit 0450e50258
7 changed files with 214 additions and 129 deletions

View File

@ -1,12 +1,12 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
activesupport (6.0.2.2) activesupport (6.0.3.4)
concurrent-ruby (~> 1.0, >= 1.0.2) concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2) i18n (>= 0.7, < 2)
minitest (~> 5.1) minitest (~> 5.1)
tzinfo (~> 1.1) tzinfo (~> 1.1)
zeitwerk (~> 2.2) zeitwerk (~> 2.2, >= 2.2.2)
addressable (2.7.0) addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0) public_suffix (>= 2.0.2, < 5.0)
coffee-script (2.4.1) coffee-script (2.4.1)
@ -16,38 +16,39 @@ GEM
colorator (1.1.0) colorator (1.1.0)
commonmarker (0.17.13) commonmarker (0.17.13)
ruby-enum (~> 0.5) ruby-enum (~> 0.5)
concurrent-ruby (1.1.6) concurrent-ruby (1.1.7)
dnsruby (1.61.3) dnsruby (1.61.5)
addressable (~> 2.5) simpleidn (~> 0.1)
em-websocket (0.5.1) em-websocket (0.5.2)
eventmachine (>= 0.12.9) eventmachine (>= 0.12.9)
http_parser.rb (~> 0.6.0) http_parser.rb (~> 0.6.0)
ethon (0.12.0) ethon (0.12.0)
ffi (>= 1.3.0) ffi (>= 1.3.0)
eventmachine (1.2.7) eventmachine (1.2.7)
execjs (2.7.0) execjs (2.7.0)
faraday (1.0.1) faraday (1.1.0)
multipart-post (>= 1.2, < 3) multipart-post (>= 1.2, < 3)
ffi (1.12.2) ruby2_keywords
ffi (1.13.1)
forwardable-extended (2.6.0) forwardable-extended (2.6.0)
gemoji (3.0.1) gemoji (3.0.1)
github-pages (204) github-pages (209)
github-pages-health-check (= 1.16.1) github-pages-health-check (= 1.16.1)
jekyll (= 3.8.5) jekyll (= 3.9.0)
jekyll-avatar (= 0.7.0) jekyll-avatar (= 0.7.0)
jekyll-coffeescript (= 1.1.1) jekyll-coffeescript (= 1.1.1)
jekyll-commonmark-ghpages (= 0.1.6) jekyll-commonmark-ghpages (= 0.1.6)
jekyll-default-layout (= 0.1.4) jekyll-default-layout (= 0.1.4)
jekyll-feed (= 0.13.0) jekyll-feed (= 0.15.1)
jekyll-gist (= 1.5.0) jekyll-gist (= 1.5.0)
jekyll-github-metadata (= 2.13.0) jekyll-github-metadata (= 2.13.0)
jekyll-mentions (= 1.5.1) jekyll-mentions (= 1.6.0)
jekyll-optional-front-matter (= 0.3.2) jekyll-optional-front-matter (= 0.3.2)
jekyll-paginate (= 1.1.0) jekyll-paginate (= 1.1.0)
jekyll-readme-index (= 0.3.0) jekyll-readme-index (= 0.3.0)
jekyll-redirect-from (= 0.15.0) jekyll-redirect-from (= 0.16.0)
jekyll-relative-links (= 0.6.1) jekyll-relative-links (= 0.6.1)
jekyll-remote-theme (= 0.4.1) jekyll-remote-theme (= 0.4.2)
jekyll-sass-converter (= 1.5.2) jekyll-sass-converter (= 1.5.2)
jekyll-seo-tag (= 2.6.1) jekyll-seo-tag (= 2.6.1)
jekyll-sitemap (= 1.4.0) jekyll-sitemap (= 1.4.0)
@ -55,7 +56,7 @@ GEM
jekyll-theme-architect (= 0.1.1) jekyll-theme-architect (= 0.1.1)
jekyll-theme-cayman (= 0.1.1) jekyll-theme-cayman (= 0.1.1)
jekyll-theme-dinky (= 0.1.1) jekyll-theme-dinky (= 0.1.1)
jekyll-theme-hacker (= 0.1.1) jekyll-theme-hacker (= 0.1.2)
jekyll-theme-leap-day (= 0.1.1) jekyll-theme-leap-day (= 0.1.1)
jekyll-theme-merlot (= 0.1.1) jekyll-theme-merlot (= 0.1.1)
jekyll-theme-midnight (= 0.1.1) jekyll-theme-midnight (= 0.1.1)
@ -66,13 +67,14 @@ GEM
jekyll-theme-tactile (= 0.1.1) jekyll-theme-tactile (= 0.1.1)
jekyll-theme-time-machine (= 0.1.1) jekyll-theme-time-machine (= 0.1.1)
jekyll-titles-from-headings (= 0.5.3) jekyll-titles-from-headings (= 0.5.3)
jemoji (= 0.11.1) jemoji (= 0.12.0)
kramdown (= 1.17.0) kramdown (= 2.3.0)
kramdown-parser-gfm (= 1.1.0)
liquid (= 4.0.3) liquid (= 4.0.3)
mercenary (~> 0.3) mercenary (~> 0.3)
minima (= 2.5.1) minima (= 2.5.1)
nokogiri (>= 1.10.4, < 2.0) nokogiri (>= 1.10.4, < 2.0)
rouge (= 3.13.0) rouge (= 3.23.0)
terminal-table (~> 1.4) terminal-table (~> 1.4)
github-pages-health-check (1.16.1) github-pages-health-check (1.16.1)
addressable (~> 2.3) addressable (~> 2.3)
@ -80,20 +82,20 @@ GEM
octokit (~> 4.0) octokit (~> 4.0)
public_suffix (~> 3.0) public_suffix (~> 3.0)
typhoeus (~> 1.3) typhoeus (~> 1.3)
html-pipeline (2.12.3) html-pipeline (2.14.0)
activesupport (>= 2) activesupport (>= 2)
nokogiri (>= 1.4) nokogiri (>= 1.4)
http_parser.rb (0.6.0) http_parser.rb (0.6.0)
i18n (0.9.5) i18n (0.9.5)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
jekyll (3.8.5) jekyll (3.9.0)
addressable (~> 2.4) addressable (~> 2.4)
colorator (~> 1.0) colorator (~> 1.0)
em-websocket (~> 0.5) em-websocket (~> 0.5)
i18n (~> 0.7) i18n (~> 0.7)
jekyll-sass-converter (~> 1.0) jekyll-sass-converter (~> 1.0)
jekyll-watch (~> 2.0) jekyll-watch (~> 2.0)
kramdown (~> 1.14) kramdown (>= 1.17, < 3)
liquid (~> 4.0) liquid (~> 4.0)
mercenary (~> 0.3.3) mercenary (~> 0.3.3)
pathutil (~> 0.9) pathutil (~> 0.9)
@ -113,14 +115,14 @@ GEM
rouge (>= 2.0, < 4.0) rouge (>= 2.0, < 4.0)
jekyll-default-layout (0.1.4) jekyll-default-layout (0.1.4)
jekyll (~> 3.0) jekyll (~> 3.0)
jekyll-feed (0.13.0) jekyll-feed (0.15.1)
jekyll (>= 3.7, < 5.0) jekyll (>= 3.7, < 5.0)
jekyll-gist (1.5.0) jekyll-gist (1.5.0)
octokit (~> 4.2) octokit (~> 4.2)
jekyll-github-metadata (2.13.0) jekyll-github-metadata (2.13.0)
jekyll (>= 3.4, < 5.0) jekyll (>= 3.4, < 5.0)
octokit (~> 4.0, != 4.4.0) octokit (~> 4.0, != 4.4.0)
jekyll-mentions (1.5.1) jekyll-mentions (1.6.0)
html-pipeline (~> 2.3) html-pipeline (~> 2.3)
jekyll (>= 3.7, < 5.0) jekyll (>= 3.7, < 5.0)
jekyll-optional-front-matter (0.3.2) jekyll-optional-front-matter (0.3.2)
@ -128,14 +130,15 @@ GEM
jekyll-paginate (1.1.0) jekyll-paginate (1.1.0)
jekyll-readme-index (0.3.0) jekyll-readme-index (0.3.0)
jekyll (>= 3.0, < 5.0) jekyll (>= 3.0, < 5.0)
jekyll-redirect-from (0.15.0) jekyll-redirect-from (0.16.0)
jekyll (>= 3.3, < 5.0) jekyll (>= 3.3, < 5.0)
jekyll-relative-links (0.6.1) jekyll-relative-links (0.6.1)
jekyll (>= 3.3, < 5.0) jekyll (>= 3.3, < 5.0)
jekyll-remote-theme (0.4.1) jekyll-remote-theme (0.4.2)
addressable (~> 2.0) addressable (~> 2.0)
jekyll (>= 3.5, < 5.0) jekyll (>= 3.5, < 5.0)
rubyzip (>= 1.3.0) jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0)
rubyzip (>= 1.3.0, < 3.0)
jekyll-sass-converter (1.5.2) jekyll-sass-converter (1.5.2)
sass (~> 3.4) sass (~> 3.4)
jekyll-seo-tag (2.6.1) jekyll-seo-tag (2.6.1)
@ -152,8 +155,8 @@ GEM
jekyll-theme-dinky (0.1.1) jekyll-theme-dinky (0.1.1)
jekyll (~> 3.5) jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0) jekyll-seo-tag (~> 2.0)
jekyll-theme-hacker (0.1.1) jekyll-theme-hacker (0.1.2)
jekyll (~> 3.5) jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0) jekyll-seo-tag (~> 2.0)
jekyll-theme-leap-day (0.1.1) jekyll-theme-leap-day (0.1.1)
jekyll (~> 3.5) jekyll (~> 3.5)
@ -187,13 +190,16 @@ GEM
jekyll (>= 3.3, < 5.0) jekyll (>= 3.3, < 5.0)
jekyll-watch (2.2.1) jekyll-watch (2.2.1)
listen (~> 3.0) listen (~> 3.0)
jemoji (0.11.1) jemoji (0.12.0)
gemoji (~> 3.0) gemoji (~> 3.0)
html-pipeline (~> 2.2) html-pipeline (~> 2.2)
jekyll (>= 3.0, < 5.0) jekyll (>= 3.0, < 5.0)
kramdown (1.17.0) kramdown (2.3.0)
rexml
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
liquid (4.0.3) liquid (4.0.3)
listen (3.2.1) listen (3.3.1)
rb-fsevent (~> 0.10, >= 0.10.3) rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10) rb-inotify (~> 0.9, >= 0.9.10)
mercenary (0.3.6) mercenary (0.3.6)
@ -202,22 +208,24 @@ GEM
jekyll (>= 3.5, < 5.0) jekyll (>= 3.5, < 5.0)
jekyll-feed (~> 0.9) jekyll-feed (~> 0.9)
jekyll-seo-tag (~> 2.1) jekyll-seo-tag (~> 2.1)
minitest (5.14.0) minitest (5.14.2)
multipart-post (2.1.1) multipart-post (2.1.1)
nokogiri (1.10.9) nokogiri (1.10.10)
mini_portile2 (~> 2.4.0) mini_portile2 (~> 2.4.0)
octokit (4.18.0) octokit (4.19.0)
faraday (>= 0.9) faraday (>= 0.9)
sawyer (~> 0.8.0, >= 0.5.3) sawyer (~> 0.8.0, >= 0.5.3)
pathutil (0.16.2) pathutil (0.16.2)
forwardable-extended (~> 2.6) forwardable-extended (~> 2.6)
public_suffix (3.1.1) public_suffix (3.1.1)
rb-fsevent (0.10.3) rb-fsevent (0.10.4)
rb-inotify (0.10.1) rb-inotify (0.10.1)
ffi (~> 1.0) ffi (~> 1.0)
rouge (3.13.0) rexml (3.2.4)
rouge (3.23.0)
ruby-enum (0.8.0) ruby-enum (0.8.0)
i18n i18n
ruby2_keywords (0.0.2)
rubyzip (2.3.0) rubyzip (2.3.0)
safe_yaml (1.0.5) safe_yaml (1.0.5)
sass (3.7.4) sass (3.7.4)
@ -228,15 +236,20 @@ GEM
sawyer (0.8.2) sawyer (0.8.2)
addressable (>= 2.3.5) addressable (>= 2.3.5)
faraday (> 0.8, < 2.0) faraday (> 0.8, < 2.0)
simpleidn (0.1.1)
unf (~> 0.1.4)
terminal-table (1.8.0) terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1) unicode-display_width (~> 1.1, >= 1.1.1)
thread_safe (0.3.6) thread_safe (0.3.6)
typhoeus (1.3.1) typhoeus (1.4.0)
ethon (>= 0.9.0) ethon (>= 0.9.0)
tzinfo (1.2.7) tzinfo (1.2.8)
thread_safe (~> 0.1) thread_safe (~> 0.1)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.7)
unicode-display_width (1.7.0) unicode-display_width (1.7.0)
zeitwerk (2.3.0) zeitwerk (2.4.1)
PLATFORMS PLATFORMS
ruby ruby

View File

@ -1,8 +1,12 @@
# pacman -Sy ruby ruby-bundler
BUNDLE := bundle
serve: serve:
${BUNDLE} exec jekyll serve -w -I -D -H 0.0.0.0 docker run -it --rm \
-v $$(pwd):/srv/jekyll \
-p 4000:4000 \
jekyll/jekyll \
jekyll serve -w -I -D -H 0.0.0.0
update: update:
${BUNDLE} update docker run -it --rm \
-v $$(pwd):/srv/jekyll \
jekyll/jekyll \
bundle update

View File

@ -9,6 +9,7 @@ repository: mediocregopher/blog.mediocregopher.com
twitter_username: mediocre_gopher twitter_username: mediocre_gopher
github_username: mediocregopher github_username: mediocregopher
rss: rss rss: rss
highlighter: rouge
plugins: plugins:
- jekyll-feed - jekyll-feed

View File

@ -6,6 +6,7 @@
<link href="//fonts.googleapis.com/css?family=Raleway:400,300,600" rel="stylesheet" type="text/css"> <link href="//fonts.googleapis.com/css?family=Raleway:400,300,600" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="{{ "/assets/normalize.css" | relative_url }}"> <link rel="stylesheet" href="{{ "/assets/normalize.css" | relative_url }}">
<link rel="stylesheet" href="{{ "/assets/skeleton.css" | relative_url }}"> <link rel="stylesheet" href="{{ "/assets/skeleton.css" | relative_url }}">
<link rel="stylesheet" href="{{ "/assets/friendly.css" | relative_url }}">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css" integrity="sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU" crossorigin="anonymous"> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css" integrity="sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU" crossorigin="anonymous">
<link rel="stylesheet" href="{{ "/assets/main.css" | relative_url }}"> <link rel="stylesheet" href="{{ "/assets/main.css" | relative_url }}">
{%- feed_meta -%} {%- feed_meta -%}

View File

@ -8,64 +8,49 @@ description: >-
[A previous post in this [A previous post in this
blog](2019-08-02-program-structure-and-composability.html) focused on a blog](2019-08-02-program-structure-and-composability.html) focused on a
framework developed to make designing component-based programs easier. In framework developed to make designing component-based programs easier. In
retrospect pattern/framework proposed was over-engineered; this post attempts to retrospect, the pattern/framework proposed was over-engineered. This post
present the same ideas but in a more distilled form, as a simple programming attempts to present the same ideas in a more distilled form, as a simple
pattern and without the unnecessary framework. programming pattern and without the unnecessary framework.
Nothing in this post will be revelatory; it's surely all been said before. But
hopefully the form it takes here will be useful to someone, as it would have
been useful to myself when I first learned to program.
## Axioms
For the sake of brevity let's assume the following: within the context of
single-process (_not_ the same as single-threaded), non-graphical programs the
following may be said:
1. A program may be thought of as a black-box with certain input and output
methods. It is the programmer's task to construct a program such that
specific inputs yield specific desired outputs.
2. A program is not complete without sufficient testing to prove it's complete.
3. Global state and global impure functions makes testing more difficult. This
can include singletons and system calls.
Any of these may be argued, but that will be left for other posts. Any of these
may be said of other types of programs as well, but that can also be left for
other posts.
## Components ## Components
Properties of components include: Many languages, libraries, and patterns make use of a concept called
"component", but in each case the meaning of "component" might be slightly
different. Therefore to begin talking about components we must first describe
specifically what is meant by "component" in this post.
1. *Creatable*: An instance of a component, given some defined set of For the purposes of this post, properties of components include:
parameters, can be created independently of any other instance of that or any
other component.
2. *Composable*: A component may be used as a parameter of another component's &nbsp;1... **Abstract**: A component is an interface consisting of one or more
instantiation. This would make it a child component of the one being methods. Being an interface, a component may have one or more implementations,
instantiated (i.e. the parent). but generally will have a primary implementation, which is used during a
program's runtime, and secondary "mock" implementations, which are only used
when testing other components.
3. *Abstract*: A component is an interface consisting of one or more methods. &nbsp;&nbsp;&nbsp;1a... A function might be considered a single-method
Being an interface, a component may have one or more implementations, but component if the language supports first-class functions.
generally will have a primary implementation, which is used during a
program's runtime, and secondary "mock" implementations, which are only used
when testing other components.
4. *Isolated*: A component may not use mutable global variables (i.e. &nbsp;2... **Creatable**: An instance of a component, given some defined set of
singletons) or impure global functions (e.g. system calls). It may only use parameters, can be created independently of any other instance of that or any
constants and variables/components given to it during instantiation. other component.
5. *Ephemeral*: A component may have a specific method used to clean up all &nbsp;3... **Composable**: A component may be used as a parameter of another
resources that it's holding (e.g. network connections, file handles, component's instantiation. This would make it a child component of the one being
language-specific lightweight threads, etc). instantiated (i.e. the parent).
5a. This cleanup method should _not_ clean up any child components given as &nbsp;4... **Isolated**: A component may not use mutable global variables (i.e.
instantiation parameters. singletons) or impure global functions (e.g. system calls). It may only use
constants and variables/components given to it during instantiation.
5b. This cleanup method should not return until the component's cleanup is &nbsp;5... **Ephemeral**: A component may have a specific method used to clean
complete. up all resources that it's holding (e.g. network connections, file handles,
language-specific lightweight threads, etc).
&nbsp;&nbsp;&nbsp;5a... This cleanup method should _not_ clean up any child
components given as instantiation parameters.
&nbsp;&nbsp;&nbsp;5b... This cleanup method should not return until the
component's cleanup is complete.
Components are composed together to create programs. This is done by passing Components are composed together to create programs. This is done by passing
components as parameters to other components during instantiation. The `main` components as parameters to other components during instantiation. The `main`
@ -128,12 +113,12 @@ fast to run, (usually) easy to formulate, and yield consistent results.
This program could instead be written as being composed of three components: This program could instead be written as being composed of three components:
* `stdin`, a construct given by the runtime which outputs a stream of bytes. * `stdin`: a construct given by the runtime which outputs a stream of bytes.
* `disk`, accepts a file name and file contents as input, writes the file * `disk`: accepts a file name and file contents as input, writes the file
contents to a file of the given name, and potentially returns an error back. contents to a file of the given name, and potentially returns an error back.
* `hashFileWriter`, reads a stream of bytes off a `stdin`, collects the stream * `hashFileWriter`: reads a stream of bytes off a `stdin`, collects the stream
into a string, hashes that string to generate a file name, and uses `disk` to into a string, hashes that string to generate a file name, and uses `disk` to
create a corresponding file with the string as its contents. If `disk` returns create a corresponding file with the string as its contents. If `disk` returns
an error then `hashFileWriter` returns that error. an error then `hashFileWriter` returns that error.
@ -201,14 +186,15 @@ gain. This is because we have not yet written tests.
## Testing ## Testing
As has already been firmly established, testing is important. Testing is important. This post won't attempt to defend that statement, that's
for another time. Let's just accept it as true for now.
In the second form of the program we can test the core-functionality of the In the second form of the program we can test the core-functionality of the
`hashFileWriter` component without resorting to using the actual `stdin` and `hashFileWriter` component without resorting to using the actual `stdin` and
`disk` components. Instead we use mocks of those components. A mock component `disk` components. Instead we use mocks of those components. A mock component
implements the same input/outputs that the "real" component does, but in a way implements the same input/outputs that the "real" component does, but in a way
which makes testing a particular component possible without reaching outside the which makes it possible to write tests of another component which don't reach
process. These are unit tests. outside the process. These are unit tests.
Tests for the latest form of the program might look like this: Tests for the latest form of the program might look like this:
@ -277,9 +263,9 @@ func TestHashFileWriter(t *testing.T) {
Notice that these tests do not _completely_ cover the desired functionality of Notice that these tests do not _completely_ cover the desired functionality of
the program: if `disk` returns an error that error should be returned from the program: if `disk` returns an error that error should be returned from
`hashFileWriter`. Whether or not this must be tested as well, and indeed the `hashFileWriter`, but this functionality is not tested. Whether or not this must
pedantry level of tests overall, is a matter of taste. I believe these to be be tested as well, and indeed the pedantry level of tests overall, is a matter
sufficient. of taste. I believe these tests to be sufficient.
## Configuration ## Configuration
@ -299,7 +285,7 @@ on the command-line, rather than reading from stdin, and second, there should be
a command-line parameter declaring which directory to write files into. The new a command-line parameter declaring which directory to write files into. The new
implementation looks like: implementation looks like:
``` ```go
package main package main
import ( import (
@ -376,12 +362,12 @@ meaning all unit tests remained valid.
A program can be split into three stages: setup, runtime, and cleanup. Setup A program can be split into three stages: setup, runtime, and cleanup. Setup
is the stage during which internal state is assembled in order to make runtime is the stage during which internal state is assembled in order to make runtime
possible. Runtime is the stage during which a program's actual function is being possible. Runtime is the stage during which a program's actual function is being
performed. Cleanup is the stage during which runtime stop and internal state is performed. Cleanup is the stage during which runtime stops and internal state is
disassembled. disassembled.
A graceful (i.e. reliably correct) setup is quite natural to accomplish, but A graceful (i.e. reliably correct) setup is quite natural to accomplish, but
unfortunately a graceful cleanup is not a programmer's first concern, and unfortunately a graceful cleanup is not a programmer's first concern (and
frequently is not a concern at all. However, when building reliable and correct frequently is not a concern at all). However, when building reliable and correct
programs, a graceful cleanup is as important as a graceful setup and runtime. A programs, a graceful cleanup is as important as a graceful setup and runtime. A
program is still running while it is being cleaned up, and it's possibly even program is still running while it is being cleaned up, and it's possibly even
acting on the outside world still. Shouldn't it behave correctly during that acting on the outside world still. Shouldn't it behave correctly during that
@ -393,7 +379,17 @@ During setup a single-threaded process (usually `main`) will construct the
"leaf" components (those which have no child components of their own) first, "leaf" components (those which have no child components of their own) first,
then the components which take those leaves as parameters, then the components then the components which take those leaves as parameters, then the components
which take _those_ as parameters, and so on, until all are constructed. The which take _those_ as parameters, and so on, until all are constructed. The
components end up assembled into a directed acyclic graph. components end up assembled into a directed acyclic graph (DAG).
In the previous examples our DAG looked like this:
```
---> stdin
/
hashFileWriter
\
---> disk
```
At this point the program will begin runtime. At this point the program will begin runtime.
@ -405,12 +401,13 @@ called until all of its parent components have been cleaned up.
Inherent to the pattern is the fact that each component will certainly be Inherent to the pattern is the fact that each component will certainly be
cleaned up before any of its child components, since its child components must cleaned up before any of its child components, since its child components must
have been instantiated first and a component will not clean up child components have been instantiated first and a component will not clean up child components
given as parameters (as-per component property 5a). given as parameters (as-per component property 5a). Therefore the pattern avoids
use-after-cleanup situations.
With go this pattern can be achieved easily using `defer`, but writing it out With go this pattern can be achieved easily using `defer`, but writing it out
manually is not so hard, as in this toy example: manually is not so hard, as in this toy example:
``` ```go
package main package main
import ( import (
@ -510,14 +507,14 @@ func main() {
In lieu of a FAQ I will attempt to premeditate criticisms of the component In lieu of a FAQ I will attempt to premeditate criticisms of the component
oriented pattern laid out in this post: oriented pattern laid out in this post:
*This seems like a lot of extra work.* **This seems like a lot of extra work.**
Building reliable programs is a lot of work, just as building reliable-anything Building reliable programs is a lot of work, just as building a
is a lot of work. Many of us work in an industry which likes to balance reliable-anything is a lot of work. Many of us work in an industry which likes
reliability (sometimes referred to by the more specious "quality") with to balance reliability (sometimes referred to by the more specious "quality")
maleability and deliverability, which naturally leads to skepticism of any with maleability and deliverability, which naturally leads to skepticism of any
suggestions which require more time spent on reliability. This is not suggestions requiring more time spent on reliability. This is not necessarily a
necessarily a bad thing, it's just how the industry functions. bad thing, it's just how the industry functions.
All that said, a pattern need not be followed perfectly to be worthwhile, and All that said, a pattern need not be followed perfectly to be worthwhile, and
the amount of extra work incurred by it can be decided based on practical the amount of extra work incurred by it can be decided based on practical
@ -525,19 +522,19 @@ considerations. I merely maintain that when it comes time to revisit some
existing code, either to fix or augment it, that the job will be notably easier existing code, either to fix or augment it, that the job will be notably easier
if the code _mostly_ follows this pattern. if the code _mostly_ follows this pattern.
*My language makes this difficult.* **My language makes this difficult.**
I don't know of any language which makes this pattern particularly easy, so I don't know of any language which makes this pattern particularly easier than
unfortunately we're all in the same boat to some extent (though I recognize that others, so unfortunately we're all in the same boat to some extent (though I
some languages, or their ecosystems, make it more difficult than others). It recognize that some languages, or their ecosystems, make it more difficult than
seems to me that this pattern shouldn't be unbearably difficult for anyone to others). It seems to me that this pattern shouldn't be unbearably difficult for
implement in any language either, however, as the only language feature needed anyone to implement in any language either, however, as the only language
is abstract typing. feature needed is abstract typing.
It would be nice to one day see a language which explicitly supported this It would be nice to one day see a language which explicitly supported this
pattern by baking the component properties in as compiler checked rules. pattern by baking the component properties in as compiler checked rules.
*This will result in over-abstraction.* **This will result in over-abstraction.**
Abstraction is a necessary tool in a programmer's toolkit, there is simply no Abstraction is a necessary tool in a programmer's toolkit, there is simply no
way around it. The only questions are "how much?" and "where?". way around it. The only questions are "how much?" and "where?".
@ -548,7 +545,7 @@ between the different abstracted types once they've been established using other
methods. Over-abstraction is the fault of the programmer, not the language or methods. Over-abstraction is the fault of the programmer, not the language or
pattern or framework. pattern or framework.
*The acronymn is CoP.* **The acronymn is CoP.**
Why do you think I've just been ackwardly using "this pattern" instead of the Why do you think I've just been ackwardly using "this pattern" instead of the
acronymn for the whole post? Better names are welcome. acronymn for the whole post? Better names are welcome.

69
assets/friendly.css Normal file
View File

@ -0,0 +1,69 @@
.highlight .hll { background-color: #ffffcc }
.highlight { background: #f0f0f0; }
.highlight .c { color: #60a0b0; font-style: italic } /* Comment */
.highlight .err { border: 1px solid #FF0000 } /* Error */
.highlight .k { color: #007020; font-weight: bold } /* Keyword */
.highlight .o { color: #666666 } /* Operator */
.highlight .ch { color: #60a0b0; font-style: italic } /* Comment.Hashbang */
.highlight .cm { color: #60a0b0; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #007020 } /* Comment.Preproc */
.highlight .cpf { color: #60a0b0; font-style: italic } /* Comment.PreprocFile */
.highlight .c1 { color: #60a0b0; font-style: italic } /* Comment.Single */
.highlight .cs { color: #60a0b0; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #A00000 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #FF0000 } /* Generic.Error */
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.highlight .gi { color: #00A000 } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.highlight .gt { color: #0044DD } /* Generic.Traceback */
.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #007020 } /* Keyword.Pseudo */
.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #902000 } /* Keyword.Type */
.highlight .m { color: #40a070 } /* Literal.Number */
.highlight .s { color: #4070a0 } /* Literal.String */
.highlight .na { color: #4070a0 } /* Name.Attribute */
.highlight .nb { color: #007020 } /* Name.Builtin */
.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
.highlight .no { color: #60add5 } /* Name.Constant */
.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */
.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */
.highlight .ne { color: #007020 } /* Name.Exception */
.highlight .nf { color: #06287e } /* Name.Function */
.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */
.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #bb60d5 } /* Name.Variable */
.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #40a070 } /* Literal.Number.Bin */
.highlight .mf { color: #40a070 } /* Literal.Number.Float */
.highlight .mh { color: #40a070 } /* Literal.Number.Hex */
.highlight .mi { color: #40a070 } /* Literal.Number.Integer */
.highlight .mo { color: #40a070 } /* Literal.Number.Oct */
.highlight .sa { color: #4070a0 } /* Literal.String.Affix */
.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */
.highlight .sc { color: #4070a0 } /* Literal.String.Char */
.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */
.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
.highlight .s2 { color: #4070a0 } /* Literal.String.Double */
.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */
.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
.highlight .sx { color: #c65d09 } /* Literal.String.Other */
.highlight .sr { color: #235388 } /* Literal.String.Regex */
.highlight .s1 { color: #4070a0 } /* Literal.String.Single */
.highlight .ss { color: #517918 } /* Literal.String.Symbol */
.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #06287e } /* Name.Function.Magic */
.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */
.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */
.highlight .il { color: #40a070 } /* Literal.Number.Integer.Long */

8
assets/skeleton.css vendored
View File

@ -307,12 +307,12 @@ li {
/* Code /* Code
*/ */
code { code {
padding: .2rem .5rem; /*padding: .2rem .5rem;*/
margin: 0 .2rem; /*margin: 0 .2rem;*/
font-size: 90%; font-size: 90%;
white-space: nowrap; white-space: nowrap;
background: #F1F1F1; /*background: #F1F1F1;
border: 1px solid #E1E1E1; border: 1px solid #E1E1E1;*/
border-radius: 4px; } border-radius: 4px; }
pre > code { pre > code {
display: block; display: block;