update everything, fix up CoP post
This commit is contained in:
parent
dbf6ebdeee
commit
0450e50258
91
Gemfile.lock
91
Gemfile.lock
@ -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
|
||||||
|
14
Makefile
14
Makefile
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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 -%}
|
||||||
|
@ -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
|
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
|
||||||
|
|
||||||
3. *Abstract*: A component is an interface consisting of one or more methods.
|
|
||||||
Being an interface, a component may have one or more implementations, but
|
|
||||||
generally will have a primary implementation, which is used during a
|
|
||||||
program's runtime, and secondary "mock" implementations, which are only used
|
program's runtime, and secondary "mock" implementations, which are only used
|
||||||
when testing other components.
|
when testing other components.
|
||||||
|
|
||||||
4. *Isolated*: A component may not use mutable global variables (i.e.
|
1a... A function might be considered a single-method
|
||||||
|
component if the language supports first-class functions.
|
||||||
|
|
||||||
|
2... **Creatable**: An instance of a component, given some defined set of
|
||||||
|
parameters, can be created independently of any other instance of that or any
|
||||||
|
other component.
|
||||||
|
|
||||||
|
3... **Composable**: A component may be used as a parameter of another
|
||||||
|
component's instantiation. This would make it a child component of the one being
|
||||||
|
instantiated (i.e. the parent).
|
||||||
|
|
||||||
|
4... **Isolated**: A component may not use mutable global variables (i.e.
|
||||||
singletons) or impure global functions (e.g. system calls). It may only use
|
singletons) or impure global functions (e.g. system calls). It may only use
|
||||||
constants and variables/components given to it during instantiation.
|
constants and variables/components given to it during instantiation.
|
||||||
|
|
||||||
5. *Ephemeral*: A component may have a specific method used to clean up all
|
5... **Ephemeral**: A component may have a specific method used to clean
|
||||||
resources that it's holding (e.g. network connections, file handles,
|
up all resources that it's holding (e.g. network connections, file handles,
|
||||||
language-specific lightweight threads, etc).
|
language-specific lightweight threads, etc).
|
||||||
|
|
||||||
5a. This cleanup method should _not_ clean up any child components given as
|
5a... This cleanup method should _not_ clean up any child
|
||||||
instantiation parameters.
|
components given as instantiation parameters.
|
||||||
|
|
||||||
5b. This cleanup method should not return until the component's cleanup is
|
5b... This cleanup method should not return until the
|
||||||
complete.
|
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
69
assets/friendly.css
Normal 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
8
assets/skeleton.css
vendored
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user