From 9f533ffd1a3d4e1ad11d71d951d9d8efcf1eadd7 Mon Sep 17 00:00:00 2001 From: James Brechtel Date: Thu, 3 Oct 2024 20:59:01 -0400 Subject: [PATCH] Some new posts --- aws-metric-filters.org | 27 ++--- big-companies.org | 15 +++ index.org | 3 +- job-description.org | 8 +- posts.org | 259 ----------------------------------------- setup.org | 12 +- vi-everywhere.org | 87 ++++++++++++++ 7 files changed, 126 insertions(+), 285 deletions(-) create mode 100644 big-companies.org delete mode 100644 posts.org diff --git a/aws-metric-filters.org b/aws-metric-filters.org index b6f98c2..882e69e 100644 --- a/aws-metric-filters.org +++ b/aws-metric-filters.org @@ -24,18 +24,14 @@ know about is AWS CloudWatch Metric Filters. If you're already on AWS then you should consider these because it requires only that your application logs to CloudWatch. -If you're on ECS then the -[[https://docs.aws.amazon.com/AmazonECS/latest/developerguide/using_awslogs.html][awslogs]] -log driver for Docker gets you that nearly for free. By "free" I mean -that your application itself can have /zero/ dependencies on AWS -services and not require any AWS credentials or libraries to start -pumping out metrics that you can visualize, alert on and record over -time. +If you're on ECS then the [[https://docs.aws.amazon.com/AmazonECS/latest/developerguide/using_awslogs.html][awslogs]] log driver for Docker gets you that +nearly for free. By "free" I mean that your application itself can +have /zero/ dependencies on AWS services and not require any AWS +credentials or libraries to start pumping out metrics that you can +visualize, alert on and record over time. -The -[[https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/MonitoringLogData.html][AWS -docs]] themselves offer the canonical reference for configuring these so -I won't go into detail here. +The [[https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/MonitoringLogData.html][AWS docs]] themselves offer the canonical reference for configuring +these so I won't go into detail here. However, the gist is that for a log filter you define the following properties @@ -47,13 +43,8 @@ properties - And finally a log group to extract the metric values from After that you just run the application and as the logs roll in the -metric values get pumped out. Then you can -[[https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Create-alarm-on-metric-math-expression.html][define -alarms for alerting]] on them, -[[https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Dashboards.html][graph -them]], -[[https://docs.aws.amazon.com/autoscaling/ec2/userguide/as-scaling-simple-step.html#policy-creating-alarm-console][define -autoscaling rules]] from them and more. +metric values get pumped out. Then you can [[https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Create-alarm-on-metric-math-expression.html][define alarms for alerting]] +on them, [[https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Dashboards.html][graph them]], [[https://docs.aws.amazon.com/autoscaling/ec2/userguide/as-scaling-simple-step.html#policy-creating-alarm-console][define autoscaling rules]] from them and more. To conclude - AWS is big and hairy. While there are benefits to staying platform agnostic, some AWS services don't require much or any coupling diff --git a/big-companies.org b/big-companies.org new file mode 100644 index 0000000..1866f73 --- /dev/null +++ b/big-companies.org @@ -0,0 +1,15 @@ +:PROPERTIES: +#+SETUPFILE: setup.org +:END: + +Organizing people is a difficult problem which only gets more difficult as youmore people need to be organized. + +The larger a company is the more of its internal structures, rules, policies, history, etc are devoted _just_ to organizing people. + +For me, realizing this was like the first time you hear a flourescent light buzzing in an otherwise quiet room. + +Reasonable people can differ on this point, but for my own sake I'd much rather avoid all the people-organizing baggage that comes with large companies. + +I don't have a hard-and-fast rule about the size of a place I want to work but the larger a place is then generally the more reason I need to want to be there. + +Of course, this is all kind of theoretical at this point, as [[https://flipstone.com][Flipstone]] is my forever home. diff --git a/index.org b/index.org index 7c4f706..d9e88a0 100644 --- a/index.org +++ b/index.org @@ -5,7 +5,8 @@ :END: * TODO [[file:let-people-fail.org][Let people fail]] -* TODO [[file:job-description.org][My job description]] +* [[file:big-companies][The problem with large organizations]] +* TODO [[file:job-description.org][Just what is it you do here?]] * TODO [[file:managing-expectations.org][Managing Expectations]] * [[file:https-at-home.org][HTTPS @ Homelab]] * [[file:multi-room-audio.org][Multi-room audio setup]] diff --git a/job-description.org b/job-description.org index 7715b32..4a2568b 100644 --- a/job-description.org +++ b/job-description.org @@ -1,6 +1,10 @@ :PROPERTIES: #+SETUPFILE: setup.org :END: -** Just what is it I do here? +** Just what is it you do here? -For my own sake, I think it's clarifying for me ot describe just what my job is. +I've never liked working at [[file:big-companies.org][larger companies]]. + +But that doesn't _always_ simplify things. + +Sometimes at smaller companies you end up defining your own job, to some degree. diff --git a/posts.org b/posts.org deleted file mode 100644 index fffcaa0..0000000 --- a/posts.org +++ /dev/null @@ -1,259 +0,0 @@ -:PROPERTIES: -#+SETUPFILE: setup.org -:END: -* Homelab :homelab: -** HTTPS @ Home -:PROPERTIES: -#+keywords: homelab -#+export_file_name: https-at-home -#+subtitle: -:END: - -I run a lot of services at home. - -This includes, but isn't limited to - -- [[https://archivebox.io/][ArchiveBox]] -- [[https://github.com/dani-garcia/vaultwarden][VaultWarden]] -- [[https://github.com/navidrome/navidrome][Navidrome]] -- [[https://plex.tv][Plex]] -- [[https://github.com/LibrePhotos/librephotos][LibrePhotos]] -- This blog - -and a lot more. - -Pretty much anything that's served up over HTTP is always nice if not -necessary to have behind TLS. - -[[https://letsencrypt.org/][LetsEncrypt]] long ago brought free certs to -the masses and there are a lot of tools for automating that nowadays. - -My preferred approach for getting all the unnecessary nonsense I -self-host at home behind TLS is [[https://caddyserver.com][Caddy]]. - -I have a super straight forward setup, generally: - -- Run Caddy in a docker container -- Create a wildcard CNAME record in my DNS pointing at my home's - (effectively) static IP -- Add an entry in my Caddyfile for each services I'm running at home on - its own subdomain -- If it's a service then I add it with a =reverse_proxy= block -- If it's a static site (like this) then there's a block for -- If it's something I want only accessible on my home network then I put - a block like - -#+BEGIN_EXAMPLE - @local_network { - path * - remote_ip - } -#+END_EXAMPLE - -in the directive. And voila. - -Then tell Caddy to reload the config and I'm done. - -** My multiroom audio setup -:PROPERTIES: -#+keywords: homelab snapcast audio -#+export_file_name: home-multiroom-audio -#+subtitle: -:END: - -I've put my home audio solution together out of the following -components. - -- [[https://github.com/badaix/snapcast][Snapcast]] - -- [[https://www.musicpd.org/][MPD]] - -- [[https://github.com/librespot-org/librespot][Librespot]] - -- [[https://github.com/mikebrady/shairport-sync][Shairport-sync]] - -- A mini-PC in my closet running the above software - -- Two Raspberry Pi 4s - -- Four Raspberry Pi Zero Ws - -- Some desktop speakers and some Bluetooth speakers (wired to the Pis) - -Each of the Raspberry Pis is in a room or porch attached to a speaker. - -Snapcast lets me take an audio source and synchronize it across multiple -clients. Each of the Raspberry Pis are running a =snapclient= instance -and play whatever the =snapserver= instance tells them to. - -Snapcast is setup to send whichever of the streams (MPD, Spotify, -Shairport-sync/AirPlay) is playing audio to each of the clients that are -connected to it. - -This lets me or anyone else on my WiFi network play directly on one or -more of the speakers - each named for the room that they're in using -either Spotify, AirPlay, picking from my own music collection or by -pointing at a URL (like to a podcast episode). - -This works out great and we've used it at home for the past year. - -I'd like to get the podcast experience to a more seamless place but it's -pretty OK right now using AirMusic on my phone to play audio to the -speakers over AirPlay. -* Tooling :tooling: -** vi modal editing in most places -:PROPERTIES: -#+keywords: vim -#+export_file_name: vi-editing-everywhere -#+subtitle: -:END: -For my sake, I prefer to have Vim bindings in as many places as -possible. - -Most shells can be configured to use Vim bindings by putting =set -o vi= -somewhere in your shell startup script. - -If you're using ZSH then you'll probably want an additional binding to -restore CTRL-R reverse history search. - -=bindkey '^R' history-incremental-search-backward= - -For CLI tools that use the =readline= library then you can configure its -input mode using a =.inputrc= file in your =$HOME= directory. - -This affects REPLs like =ghci= and tools like =psql=. - -#+begin_src txt -set editing-mode vi -$if mode=vi - -set keymap vi-command -# these are for vi-command mode -Control-l: clear-screen - -set keymap vi-insert -# these are for vi-insert mode -Control-l: clear-screen -$endif -#+end_src - -* AWS :aws: -** Structed and passively collected metrics via AWS CloudWatch -:PROPERTIES: -#+keywords: aws -#+export_file_name: aws-cloudwatch-metric-filters -#+subtitle: -:END: - -AWS is a vast and sprawling set of services. It can be hard to find the -hidden gems like this one so I wanted to point this one out. - -Structured metrics are very helpful to monitoring the health and -function of an software system. - -- Do you want to know how long a particular transaction typically takes? -- How fast your database queries are? -- How long external APIs take to respond? -- Fire an alert when a particular function on the site happens too many - times? Or too few times? - -...plus a million other things specific to whatever system you're -working on. - -There are a lot of great tools for doing this and one that you might not -know about is AWS CloudWatch Metric Filters. If you're already on AWS -then you should consider these because it requires only that your -application logs to CloudWatch. - -If you're on ECS then the -[[https://docs.aws.amazon.com/AmazonECS/latest/developerguide/using_awslogs.html][awslogs]] -log driver for Docker gets you that nearly for free. By "free" I mean -that your application itself can have /zero/ dependencies on AWS -services and not require any AWS credentials or libraries to start -pumping out metrics that you can visualize, alert on and record over -time. - -The -[[https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/MonitoringLogData.html][AWS -docs]] themselves offer the canonical reference for configuring these so -I won't go into detail here. - -However, the gist is that for a log filter you define the following -properties - -- A filter pattern for extracting a discrete metric value out of a log - entry -- A metric name to store the value in -- An optional dimension for sub-classifying the value -- And finally a log group to extract the metric values from - -After that you just run the application and as the logs roll in the -metric values get pumped out. Then you can -[[https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Create-alarm-on-metric-math-expression.html][define -alarms for alerting]] on them, -[[https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Dashboards.html][graph -them]], -[[https://docs.aws.amazon.com/autoscaling/ec2/userguide/as-scaling-simple-step.html#policy-creating-alarm-console][define -autoscaling rules]] from them and more. - -To conclude - AWS is big and hairy. While there are benefits to staying -platform agnostic, some AWS services don't require much or any coupling -of your application code to take advantage of. Cloudwatch Metrics is one -of those services and you can get a lot of value out of it with not much -effort. - -* Musings :musings: -** TODO My job description -** TODO Managing expectations -** TODO Just let people be wrong -:PROPERTIES: -#+keywords: advice relationships people -#+export_file_name: let-people-fail -#+subtitle: -:END: - -Warning: This, like most things, will involve a fair bit of projection. - -I have some thoughts about collaboration. - -While a lot of this is obvious and well accepted, I think there are some fine points worth elaborating on. - -The obvious part is that people work better together when they believe they are trusted. Trust breeds initiative and independence. Distrust breeds resentment and inaction. - -Consider the flip side of trust, for a moment. - -A common way that people show _distrust_ when collaborating is either micromanaging or just coming in behind someone and redoing their work. - -If that demonstrates distrust then - -It's not enough that you simply _do_ trust someone else to get the benefits, you need to show it. I think this is the part that many people skip or ignore. - -This is, of course, true in general. - -** Very simple CSS frameworks -:PROPERTIES: -#+keywords: CSS -#+export_file_name: css-frameworks -#+subtitle: -:END: - -*** Minimal CSS / fancy resets -I really like simple drop-in CSS resets like the one I use for this site. - -At the time of writing, I'm using [[https://picocss.com/][Pico]] but I also considered [[https://yegor256.github.io/tacit/][tacit]] - -The idea is that they provide nice default styling of HTML elements out of the box without the need to reference any specific classes. - -The idea works well for sites that are much more content than layout - like this one. - -Using tacit is a matter of incluing this link tag in the page's HEAD element: - -#+BEGIN_SRC html - -#+END_SRC - -#+BEGIN_SRC haskell - doThings :: String -> IO () - doThings name = do - putStrLn name -#+END_SRC diff --git a/setup.org b/setup.org index c3d516d..537a5db 100644 --- a/setup.org +++ b/setup.org @@ -2,17 +2,19 @@ #+author: James Brechtel #+email: me@jamesbrechtel.com #+bind: org-export-publishing-directory "./public" -#+html_head_x: -#+html_headxx: -#+html_head_bahunya: +#+html_headx: #+html_head: +#+html_head_writ: +#+html_head_bahunya: +#+html_head_awsm: #+html_head_simple: #+html_head_holiday: -#+html_head_mvp: +#+html_head_mvp: #+html_head_pico: +#+html_head: #+html_head_tacit: #+options: html-link-use-abs-url:nil html-postamble:nil -#+options: html-preamble:t html-scripts:nil html-style:t +#+options: html-preamble:t html-scripts:nil html-style:nil #+options: html5-fancy:t tex:t #+options: author:t broken-links:mark c:nil creator:nil f:t tasks:t toc:nil todo:t #+OPTIONS: num:nil diff --git a/vi-everywhere.org b/vi-everywhere.org index bcbaa3a..62d9d4d 100644 --- a/vi-everywhere.org +++ b/vi-everywhere.org @@ -4,6 +4,8 @@ #+subtitle: :END: ** vi modal editing in most places +#+HTML:
+#+HTML:
For my sake, I prefer to have Vim bindings in as many places as possible. @@ -19,6 +21,8 @@ For CLI tools that use the =readline= library then you can configure its input mode using a =.inputrc= file in your =$HOME= directory. This affects REPLs like =ghci= and tools like =psql=. +#+HTML:
+#+HTML:
#+begin_src txt set editing-mode vi @@ -34,3 +38,86 @@ Control-l: clear-screen $endif #+end_src + +#+BEGIN_SRC haskell +module Data.Validation.Aeson where + +import Control.Monad.Identity + +import Data.Aeson +import qualified Data.Aeson.Key as Key +import qualified Data.Aeson.KeyMap as KeyMap +import qualified Data.ByteString as BS +import qualified Data.ByteString.Lazy as LazyBS +import qualified Data.Map.Strict as Map +import qualified Data.Set as Set +import qualified Data.Text as Text +import qualified Data.Vector as Vec + +import Data.Validation.Types + +decodeValidJSON :: Validator Value a -> LazyBS.ByteString -> ValidationResult a +decodeValidJSON validator input = + runIdentity (decodeValidJSONT (liftV validator) input) + +decodeValidJSONStrict :: Validator Value a -> BS.ByteString -> ValidationResult a +decodeValidJSONStrict validator input = + runIdentity (decodeValidJSONStrictT (liftV validator) input) + +decodeValidJSONT :: + Applicative m => + ValidatorT Value m a -> + LazyBS.ByteString -> + m (ValidationResult a) +decodeValidJSONT validator input = + case eitherDecode input of + Left err -> pure $ Invalid (errMessage $ Text.pack err) + Right value -> runValidatorT validator (value :: Value) + +decodeValidJSONStrictT :: + Applicative m => + ValidatorT Value m a -> + BS.ByteString -> + m (ValidationResult a) +decodeValidJSONStrictT validator input = + case eitherDecodeStrict input of + Left err -> pure $ Invalid (errMessage $ Text.pack err) + Right value -> runValidatorT validator (value :: Value) + +instance Validatable Value where + inputText (String text) = Just text + inputText _ = Nothing + + inputNull Null = IsNull + inputNull _ = NotNull + + inputBool (Bool True) = Just True + inputBool (Bool False) = Just False + inputBool _ = Nothing + + arrayItems (Array items) = Just items + arrayItems _ = Nothing + + scientificNumber (Number sci) = Just sci + scientificNumber _ = Nothing + + lookupChild attrName (Object hmap) = + LookupResult $ + KeyMap.lookup (Key.fromText attrName) hmap + lookupChild _ _ = InvalidLookup + +instance ToJSON Errors where + toJSON (Messages set) = + Array + . Vec.fromList + . map toJSON + . Set.toList + $ set + toJSON (Group attrs) = + Object + . KeyMap.fromList + . Map.toList + . Map.mapKeys Key.fromText + . Map.map toJSON + $ attrs +#+END_SRC