reworkify
60
2024.html
@@ -1,60 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>2024</title>
|
||||
<meta name="description" value="Plans for 2024">
|
||||
</head>
|
||||
<body style="margin: 0; padding: 0; background-color: rgb(254, 249, 232)">
|
||||
<div style="margin: 48px; width: 580px;">
|
||||
<a href="/"><< back</a>
|
||||
<h1>2024</h1>
|
||||
<p>
|
||||
2023 was a good year, but now it's 2024. Here's some of my technical plans for 2024.
|
||||
</p>
|
||||
<p>
|
||||
<b>NOTE</b>: These are in no particular order.
|
||||
</p>
|
||||
<h2>Technology I plan to use in 2024</h2>
|
||||
<ul>
|
||||
<li>C++23</li>
|
||||
<li>Perl 5.38 (Corrina!)</li>
|
||||
<li>Raku</li>
|
||||
<li>OCaml</li>
|
||||
<li>Go</li>
|
||||
<li>HTMX</li>
|
||||
<li>Mojolicious</li>
|
||||
<li>PostgreSQL</li>
|
||||
<li>Memcached</li>
|
||||
</ul>
|
||||
<h2>Technology I want to learn more about in 2024</h2>
|
||||
<ul>
|
||||
<li>C++23</li>
|
||||
<li>Clojure</li>
|
||||
<li>Lua</li>
|
||||
<li>FreeBSD</li>
|
||||
<li>Caddy</li>
|
||||
</ul>
|
||||
<h2>Technology I might learn in 2024</h2>
|
||||
<ul>
|
||||
<li>Common Lisp</li>
|
||||
<li>Elixir</li>
|
||||
<li>DragonflyBSD</li>
|
||||
<li>FirebirdSQL</li>
|
||||
<li>Nim</li>
|
||||
</ul>
|
||||
<h2>Technology I won't learn in 2024</h2>
|
||||
<p>
|
||||
It's not that I hate the following, it's just that they don't really interest me,
|
||||
or the people behind them do not seem to value people using them (ala Rust).
|
||||
</p>
|
||||
<ul>
|
||||
<li>Rust</li>
|
||||
<li>Next.JS</li>
|
||||
<li>Zig</li>
|
||||
<li>Kubernetes</li>
|
||||
<li>Terraform</li>
|
||||
</ul>
|
||||
<p>Have a safe and fun 2024.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 9.7 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
@@ -1,84 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Become a software engineer</title>
|
||||
<meta name="description" value="How to become a software engineer. The real way.">
|
||||
</head>
|
||||
<body style="margin: 0; padding: 0; background-color: rgb(254, 249, 232)">
|
||||
<div style="margin: 48px; width: 580px;">
|
||||
<a href="/"><< back</a>
|
||||
<h1>Become an Engineer</h1>
|
||||
<p>
|
||||
This learning track assumes you have a computer built after 2004, with
|
||||
<a href="https://debian.org">Debian Linux</a>, <a href="https://freebsd.org">FreeBSD</a> or <a href="https://openbsd.org">OpenBSD</a> installed. (Windows simply won't do.)
|
||||
</p>
|
||||
<h2>Start here (read both and do all of the exercises)</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://mitp-content-server.mit.edu/books/content/sectbyfn/books_pres_0/6515/sicp.zip/index.html">Structure and Interpretation of Computer Programs by Sussman et. al</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://en.wikipedia.org/wiki/The_C_Programming_Language">The C Programming Language by K&R</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h2>Getting deeper (read all 3, do all exercises)</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://algs4.cs.princeton.edu/home/">Algorithms by Robert Sedgewick</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://en.wikipedia.org/wiki/Types_and_Programming_Languages">Types and Programming Languages by Benjamin C. Pierce</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://www.macs.hw.ac.uk/~greg/books/gjm.lambook88.pdf">An Introduction to Functional Programming Through Lambda Calculus by Greg Michaelson</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h2>Low level learning</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://mitpress.mit.edu/9780262640688/the-elements-of-computing-systems/">The Elements of Computing Systems by Noam Nisan and Shimon Schocken</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h2>Category theory</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://bartoszmilewski.com/2014/10/28/category-theory-for-programmers-the-preface/">Category Theory for Programmers by Bartosz Milewski</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h2>High(er) Level Languages (pick at least 2)</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://www.oreilly.com/library/view/programming-perl-4th/9781449321451/">Programming Perl by Christiansen, foy, and Orwant</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://learnyousomeerlang.com/">Learn You Some Erlang for Great Good by Fred Hebert</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://learnyouahaskell.com/">Learn You a Haskell for Great Good by Miran Lipovaca</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://www.stroustrup.com/tour2.html">A Tour of C++ by Stroustrup</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://www.cs.cmu.edu/~rwh/isml/book.pdf">Programming in Standard ML by Robert Harper</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://www.oreilly.com/library/view/the-ruby-programming/9780596516178/">The Ruby Programming Language by Flanagan & Matz</a>
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
This is the way to becoming a truly great software engineer. I've read all of these books, and I can say that they all manifest within
|
||||
me a strong sense of confidence, and the ability to adapt to any situation that might come my way in computer science.
|
||||
</p>
|
||||
<p>
|
||||
You may be reading this list, thinking... what about Java or JavaScript??? Now, I don't think these languages are bad per-se, but I do think
|
||||
they have the ability to destroy your life. Once you've used Java or JavaScript, there is a good chance you will become closed off from
|
||||
the rest of the computing world, falling into a world of patterns and objects. You may also find that languages like these have the adverse
|
||||
effect of having incredibly low skill-ceilings, which compounds the idea of you becoming stuck. A low ceiling, and a low floor, is a prison, not
|
||||
a tool to conjure the spirits of the computer.
|
||||
</p>
|
||||
<br>
|
||||
<br>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,73 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Dancer2::Controllers</title>
|
||||
<meta name="description" value="How to use Dancer2::Controllers for Perl's webframework, Dancer2.">
|
||||
<meta name="keywords" value="Perl, Perl5, Dancer, Dancer2, Controllers, MVC, Spring-Boot">
|
||||
</head>
|
||||
<body style="margin: 0; padding: 0; background-color: rgb(254, 249, 232)">
|
||||
<div style="margin: 48px; width: 580px;">
|
||||
<a href="/"><< back</a>
|
||||
<h1>Dancer2::Controllers and Perl Attributes</h1>
|
||||
<p>Published February 26th, 2024.</p>
|
||||
<p>
|
||||
Recently I created <a href="https://metacpan.org/pod/Dancer2::Controllers"><code>Dancer2::Controllers</code></a>, a simple
|
||||
<code>Moose</code> based approach for defining routes in Dancer2. I built this as an attempt to add Spring-Boot esq annotations to
|
||||
Dancer2.
|
||||
</p>
|
||||
<h2>The approach</h2>
|
||||
<p>
|
||||
Perl has a little know feature called "Attributes", which work as some extra arbitrary data appended to
|
||||
the various reftypes in Perl. When you append an Attribute, Perl looks for the <code>MODIFY_<reftype>_ATTRIBUTES</code> in the current
|
||||
namespace, and uses it to decide if that attribute is allowed, and lets you execute some arbitrary code as well. Perl attributes can also take "arguments".
|
||||
These "arguments" actually are just part of the Attribute, and you need to parse the entire Attribute to get the arguments.
|
||||
</p>
|
||||
<p>
|
||||
Since Perl Attributes are the closest thing I could find to annotations, I decided a generic <code>Route</code> attribute would be nice.
|
||||
With a Perly looking argument pattern: <code>Route(get => /foo)</code>, this feels a Perl version of Spring-Boot's
|
||||
<code>@RequestMapping(value = "/foo", method = GET)</code>,
|
||||
which is exactly what I was looking for.
|
||||
</p>
|
||||
<h2>Speed Bumps</h2>
|
||||
<p>
|
||||
Dancer2 is built on-top of <code>Moo</code>, unfortunately I couldn't find a nice way to handle Attributes using Moo, and inheritance. So, I settled for adding
|
||||
<code>Moose</code> and the wonderfully helpful <code>MooseX::MethodAttributes</code> dist, which drastically simplified the work I needed to do.
|
||||
</p>
|
||||
<h2>In action</h2>
|
||||
<p>The following is an example of how to use <code>Dancer2::Controllers</code></p>:
|
||||
<pre>
|
||||
<code>
|
||||
package My::Controller;
|
||||
|
||||
use Moose;
|
||||
|
||||
BEGIN { extends 'Dancer2::Controllers::Controller' }
|
||||
|
||||
sub home_page : Route(get => /home) {
|
||||
my $app = shift;
|
||||
my $user_name = $app->session('user');
|
||||
return "Welcome back $user_name!";
|
||||
}
|
||||
|
||||
sub home_page : Route(post => /login) {
|
||||
my $app = shift;
|
||||
my $password = $app->body_parameters->get('password');
|
||||
return "Here is your password: $password";
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
package main;
|
||||
|
||||
use Dancer2;
|
||||
use Dancer2::Controllers;
|
||||
|
||||
controllers([ 'My::Controller' ]);
|
||||
|
||||
dance;
|
||||
</code>
|
||||
</pre>
|
||||
<p>Thanks for reading :)</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,143 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Running mod_perl with Mojolicious in Docker</title>
|
||||
<meta name="description" content="Running Apache mod_perl and Mojolicious in Docker">
|
||||
<meta name="keywords" content="mojolicious mojo mod_perl docker apache">
|
||||
<meta charset="UTF-8">
|
||||
</head>
|
||||
<body style="margin: 0; padding: 0; background-color: rgb(254, 249, 232)">
|
||||
<div style="margin: 48px; width: 530px;">
|
||||
<a href="/"><< back</a>
|
||||
<h1 id="running-mod_perl-with-mojolicious-in-docker">Running mod_perl with Mojolicious in Docker</h1>
|
||||
<p>
|
||||
I've been working under an old Apache <code>mod_perl</code> setup. I wanted to use Mojolicious for some new services,
|
||||
but I needed to stay within <code>mod_perl</code>, so I decided to go all the way and Dockerize it. After scouring the <code>mod_perl</code> documentation,
|
||||
Plack + Mojolicious configs, and finding an image, I hit the ground running and documented my steps.
|
||||
</p>
|
||||
<a href="http://perl.apache.org/">
|
||||
<img src="mod_perl.gif" alt="mod_perl banner" />
|
||||
</a>
|
||||
<p>I love old banners :)</p>
|
||||
<h3 id="generate-your-config">Generate your config</h3>
|
||||
<p>Thanks to <a href="https://github.com/motemen/docker-mod_perl">motemen</a> for some nicely pre-configured
|
||||
<code>mod_perl</code> and <code>Apache2</code> images. We're targetting <code>Perl v5.36</code>, and <code>Apache 2.4.58</code> here.
|
||||
We'll also add the include statement for our <code>VirtualHost</code> configuration file that we'll make later.
|
||||
</p>
|
||||
<pre>
|
||||
<code>docker <span class="hljs-keyword">run</span> --<span class="hljs-keyword">rm</span> motemen/mod_perl:5.36.0-2.4.58 <span class="hljs-keyword">cat</span> /usr/<span class="hljs-keyword">local</span>/apache2/<span class="hljs-keyword">conf</span>/httpd.<span class="hljs-keyword">conf</span> > httpd.<span class="hljs-keyword">conf</span>
|
||||
echo '<span class="hljs-keyword">Include</span> /usr/<span class="hljs-keyword">local</span>/apache2/<span class="hljs-keyword">conf</span>/mojolicious.<span class="hljs-keyword">conf</span>' >> httpd.<span class="hljs-keyword">conf</span>
|
||||
</code>
|
||||
</pre>
|
||||
<p>
|
||||
This will leave you with a <code>httpd.conf</code> that will get picked up by Apache when we run it under docker.
|
||||
</p>
|
||||
<h3 id="enable-prefork-mpm-instead-of-event-mpm">Enable Prefork MPM instead of Event MPM</h3>
|
||||
<p>
|
||||
I couldn't get Apache to run without disabling Event MPM and enabling Prefork MPM.
|
||||
</p>
|
||||
<p>In <code>httpd.conf</code>:</p>
|
||||
<pre>
|
||||
<code>
|
||||
<span class="hljs-selector-id">#LoadModule</span> mpm_event_module modules/mod_mpm_event<span class="hljs-selector-class">.so</span>
|
||||
LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
|
||||
</code>
|
||||
</pre>
|
||||
<h3 id="write-your-application">Write your application</h3>
|
||||
<p>
|
||||
All you need to do is write a Mojo application. In this case, I'm using <code>Mojolicious::Lite</code> but this can
|
||||
be done with the whole MVC setup easily as well. Just make sure you have a sub that returns your <code>app</code> so you can
|
||||
pass it to <code>Plack::Builder</code>.
|
||||
</p>
|
||||
<p>In <code>lib/App.pm</code>:</p>
|
||||
<pre>
|
||||
<code class="lang-perl">
|
||||
<span class="hljs-keyword">package</span> App;
|
||||
<span class="hljs-keyword">use</span> <span class="hljs-number">5.036</span>;
|
||||
<span class="hljs-keyword">use</span> Mojolicious::Lite -signatures;
|
||||
|
||||
<span class="hljs-function"><span class="hljs-keyword">sub</span> <span class="hljs-title">get_app</span> </span>{ app; }
|
||||
|
||||
get <span class="hljs-string">'/'</span> => <span class="hljs-function"><span class="hljs-keyword">sub</span> </span>{
|
||||
<span class="hljs-keyword">shift</span>->render( <span class="hljs-string">text =></span> <span class="hljs-string">"Hello World!"</span> );
|
||||
};
|
||||
|
||||
<span class="hljs-number">1</span>;
|
||||
</code></pre>
|
||||
<h3 id="write-your-plack-shim">Write your Plack shim</h3>
|
||||
<p>
|
||||
Here we write a simple <code>.psgi</code> file that
|
||||
will use our <code>App</code> library and <code>Plack::Builder</code> to
|
||||
create a <code>PSGI</code> application for <code>Plack::Handler::Apache2</code> to pickup.
|
||||
</p>
|
||||
<p>In <code>app.psgi</code>:</p>
|
||||
<pre>
|
||||
<code>use <span class="hljs-number">5.036</span>;
|
||||
|
||||
use <span class="hljs-class"><span class="hljs-keyword">lib</span> '<span class="hljs-title">lib</span>';</span>
|
||||
use App;
|
||||
use Plack::Builder;
|
||||
|
||||
builder {
|
||||
<span class="hljs-symbol">App:</span>:get_app->start;
|
||||
};
|
||||
</code>
|
||||
</pre>
|
||||
<h3 id="write-your-mod_perl-apache-conf">Write your mod_perl Apache config</h3>
|
||||
<p>
|
||||
Very straight-forward, just tell Apache where to find our script, and what handler to use.
|
||||
</p>
|
||||
<p>In <code>mojolicious.conf</code>:</p>
|
||||
<pre>
|
||||
<code>
|
||||
<span class="hljs-attribute"><span class="hljs-nomarkup">LoadModule</span></span> perl_module modules/mod_perl.so
|
||||
|
||||
<span class="hljs-section"><VirtualHost *:80></span>
|
||||
<span class="hljs-section"><Location /></span>
|
||||
<span class="hljs-attribute"><span class="hljs-nomarkup">SetHandler</span></span> perl-script
|
||||
<span class="hljs-attribute">PerlResponseHandler</span> Plack::Handler::Apache2
|
||||
<span class="hljs-attribute">PerlSetVar</span> psgi_app /app.psgi
|
||||
<span class="hljs-section"></Location></span>
|
||||
<span class="hljs-section"></VirtualHost></span>
|
||||
</code>
|
||||
</pre>
|
||||
|
||||
<h3 id="write-your-dockerfile">Write your Dockerfile</h3>
|
||||
<p>
|
||||
Now all thats left is making a <code>Dockerfile</code>.
|
||||
We'll use one of <a href="https://github.com/motemen/docker-mod_perl">motemen</a>'s images,
|
||||
and copy all of the pre-reqs over, install some libraries, you know, Docker stuff.
|
||||
</p>
|
||||
<p>In <code>Dockerfile</code>:</p>
|
||||
<pre>
|
||||
<code class="lang-docker">
|
||||
<span class="hljs-keyword">FROM</span> motemen/mod_perl:<span class="hljs-number">5.36</span>.<span class="hljs-number">0</span>-<span class="hljs-number">2.4</span>.<span class="hljs-number">58</span>-<span class="hljs-number">2.0</span>.<span class="hljs-number">13</span>
|
||||
<span class="hljs-keyword">COPY</span><span class="bash"> app.psgi /app.psgi
|
||||
</span><span class="hljs-keyword">COPY</span><span class="bash"> lib /usr/<span class="hljs-built_in">local</span>/apache2/lib
|
||||
</span><span class="hljs-keyword">COPY</span><span class="bash"> httpd.conf /usr/<span class="hljs-built_in">local</span>/apache2/conf/httpd.conf
|
||||
</span><span class="hljs-keyword">COPY</span><span class="bash"> mojolicious.conf /usr/<span class="hljs-built_in">local</span>/apache2/conf/mojolicious.conf
|
||||
</span><span class="hljs-keyword">RUN</span><span class="bash"> apt-get update -y && apt-get install -y wget make build-essential
|
||||
</span><span class="hljs-keyword">RUN</span><span class="bash"> cpan -iT Plack Mojolicious
|
||||
</span><span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">80</span>
|
||||
<span class="hljs-keyword">CMD</span><span class="bash"> [<span class="hljs-string">"httpd-foreground"</span>]</span>
|
||||
</code>
|
||||
</pre>
|
||||
|
||||
<h3 id="run-with-docker">Run with Docker</h3>
|
||||
<p>Now we can make it go!</p>
|
||||
<pre>
|
||||
<code class="lang-shell"><span class="hljs-symbol">$</span> docker build . -t <span class="hljs-built-in">mod</span>-perl
|
||||
<span class="hljs-symbol">$</span> docker run -p <span class="hljs-number">80</span>:<span class="hljs-number">80</span> <span class="hljs-built-in">mod</span>-perl
|
||||
<span class="hljs-symbol">$</span> curl http:<span class="hljs-comment">//localhost:80/</span>
|
||||
|
||||
"Hello World!"
|
||||
</code>
|
||||
</pre>
|
||||
<h3 id="running-with-auto-reloading-for-development-">Running with auto-reloading (for development)</h3>
|
||||
<p>You can make this auto-reload if you use a docker volume for <code>lib/</code> against <code>/usr/local/apache2/lib/</code></p>
|
||||
<h3 id="source-code">An example?</h3>
|
||||
<p>
|
||||
An <a href="https://github.com/rawleyfowler/mojolicious-mod-perl-example">example</a> is available on my github.
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
53
emacs.html
@@ -1,53 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Emacs</title>
|
||||
<meta charset="UTF-8">
|
||||
</head>
|
||||
<body style="margin: 0; padding: 0; background-color: rgb(254, 249, 232)">
|
||||
<div style="margin: 48px; width: 580px;">
|
||||
<a href="/"><< back</a>
|
||||
<h1>Why Emacs?</h1>
|
||||
<p>
|
||||
I reccommend GNU Emacs (not Spacemacs, or Doom Emacs) to everyone. If you're just starting to program
|
||||
then you're at an even bigger advantage if you pickup Emacs early. If you're a battle hardened developer
|
||||
you should still be using Emacs, though it may be harder to pickup, assuming you've been using modern "IDE's"
|
||||
for most of your career. I also recommend Emacs to pretty much anyone that processes text often.
|
||||
</p>
|
||||
<p>
|
||||
Emacs provides the perfect balance of customization, to effectiveness of any editor. I think that it's foolish
|
||||
to use tools that don't let you mold them to <b>your</b> idea of how to use them. Software tools aren't like traditional
|
||||
tools like Hammers and Pipe-wrenches, and it's foolish to use them in this way. With Emacs a <a href="https://www.gnu.org/gnu/rms-lisp.en.html">Secretary</a>, Software Engineer (obviously),
|
||||
Math Student, Professor, <a href="https://www.masteringemacs.org/article/how-to-write-a-book-in-emacs">Novelist</a>, etc, can all find ways to implement Emacs into their day-to-day.
|
||||
Emacs is a tool for empowering <b>people</b>. It's not just a text-processor (though it's really good at that), it's also a journal,
|
||||
a lisp interpreter, and really, anything you want.
|
||||
</p>
|
||||
<h1>For Software</h1>
|
||||
<p>
|
||||
I'm going to focus on Software Developers for the rest of this, seeing as it's who I can relate too most.
|
||||
Software Developers often get stuck in ruts, I truly think Emacs is the tool to pull you out and keep you out
|
||||
of said ruts. Emacs will kick you in the rear, and make you cry, and force you to work in a subpar fashion for a long time,
|
||||
the GNU is not an easy beast to tame. But once you've put in the work, and elevated yourself upon it's reigns, the power you
|
||||
attain is so incredibly wizard-like that you may very well consider wearing a pointed hat, and robes, at work.
|
||||
</p>
|
||||
<p>
|
||||
Currently, I use Emacs for everything at work. Compiling, code editing, file-system stuff, docker, git, documentation, etc.
|
||||
I've used other editors and <b>nothing</b>, comes even close to Emacs. Vim users will probably recoil, but Vim makes you context
|
||||
switch so often between the terminal and your editor that I really think it doesn't even belong in the same category as Emacs.
|
||||
What I would recommend to the Emacs novice, is to focus on setting up your workflows 1 flow at a time. For instance, say you want
|
||||
to work on Perl code. Setup all the Perl related stuff in one-shot and don't worry about making your configuration super ergonomic
|
||||
and extensible. Just make it work for Perl. Then say, you get a job in Scala, do the same thing, but refactor your configuration
|
||||
to enable both Perl and Scala nicely, rinse and repeat until your hands bleed. That's really all there is to it, as you find things
|
||||
you want to improve, improve them one-by-one. Don't rush in and expect to setup a perfect IDE for every language and every workflow.
|
||||
Emacs really is what you make of it, but you can't really know what to make of it, until you identify the problems you want to solve.
|
||||
</p>
|
||||
<p>
|
||||
A good way to think of Emacs, is, it's the instrument equivalent of text-processors.
|
||||
</p>
|
||||
<h4>Links:</h4>
|
||||
<ul>
|
||||
<li><a href="https://github.com/rawleyfowler/emacs">My Emacs</a></li>
|
||||
<li><a href="https://emacs.amodernist.com/">Config Generator</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,104 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>How to Properly Use Global Variables</title>
|
||||
<meta name="description" value="In defense of global variables. Why globals should be considered over more complex solutions. And how to use them!">
|
||||
</head>
|
||||
<body style="margin: 0; padding: 0; background-color: rgb(254, 249, 232)">
|
||||
<div style="margin: 48px; width: 580px;">
|
||||
<a href="/"><< back</a>
|
||||
<h1>How to Properly Use Global Variables</h1>
|
||||
<p>
|
||||
Global variables, and global state in general have been under fire for as long as I can remember.
|
||||
The argument is, you couple, and introduce unpredictability through managing global variables
|
||||
since "anyone can update them". This makes sense in a cosmological world, filled with people
|
||||
who WANT to write bad code. It's not the global variables that make code bad, it's how they're used.
|
||||
We've spent many years inventing abstraction after abstraction, that could just be boiled down to global variables,
|
||||
and global constants. In the end, applications will always have global state, why make it so dang difficult?
|
||||
</p>
|
||||
<h2>Simplicity, and avoiding traps</h2>
|
||||
<p>
|
||||
Globals are simple, so simple, that even the thought of using them might turn people off. It's hard to accept
|
||||
that the simplest answer is always the best one, but it almost always is. 99% of the code I run into, is complex for the sake of "reusability", "readability", or
|
||||
"scalability", but in the end none of these come to pass. You'll see interfaces, and abstract classes defined for single implementations,
|
||||
horribly generic code written in obscure places, and a mess of a file structure with hundreds of files. Do you really need a generic interface for
|
||||
each of your database tables, or what about a "service" for each "domain"? In reality, the most readable, resuable, and scalable code, is the code that
|
||||
compiles well, and avoids mentally expensive abstraction. If I have to walk through the inheritence graph to figure out what something is doing, it's already neither
|
||||
scalable, or readable.
|
||||
</p>
|
||||
<p>
|
||||
You'll often see global variables hidden behind some "global context" like abstraction. This is down right deplorable, instead, hide your globals behind the simplest
|
||||
abstraction on the market, the function. <code>GetDatabaseHandler()</code> is much simpler to reason about than <code>GlobalContextHolder.getSingleton().getContext("database")</code>.
|
||||
These abstractions also, are prone to error, for instance if you use a hash-table to lookup values with a string key, what happens if I miss type the string? The compiler
|
||||
won't catch that for you, and you'd be adding a lot of extra instructions just to access some state somewhere (which at its fastest is a pointer dereference). Another common way to do this,
|
||||
is to pass a class object, <code>.class</code> in Java. However, this is even worse. Typically, a language will use reflection which or runtime type checks which can be extraordinarily slow.
|
||||
To compound this, you also have no gurantees on the existence of the values, for instance, if you want a <code>DatabaseHandler</code>, and you make the request for it, you have no idea
|
||||
if that is actually the right name or class until runtime. Contrast that with a function that will be picked up by your LSP or produce a compile-time error message.
|
||||
Global contexts, and contexts in general are a huge mess of slow, hard to optimize code, you should avoid them at all costs.
|
||||
</p>
|
||||
<h2>What to do instead</h2>
|
||||
<p>
|
||||
As mentioned earlier, global state should exist one layer under a function. There is absolutely nothing wrong with running a <code>database.InitializeDatabase()</code> function, to
|
||||
initialize your globals at startup, or having some sort of lazy-init built into your global accessor function. Keeping things simple is how you keep them readable, and scalable.
|
||||
What's funny, is that's pretty much it.
|
||||
</p>
|
||||
<p>
|
||||
Another thing I recommend is not accessing your globals inside of your functions, instead, pass them as arguments. This is just good-practice in general, your functions should
|
||||
do their best to be as pure as possible. This also makes your code truly re-usable and adaptable, since you may have multiple different global variables with the same types.
|
||||
This also makes your code easy to test, since it's not relying on any outside values existing or not.
|
||||
</p>
|
||||
<h2>Examples</h2>
|
||||
<p>
|
||||
Let's compare some code. In the first example, we'll do the traditional <code>GlobalContextHolder</code> OOP style,
|
||||
where we literally do our best to make it look like we're not working on global variables. In the second example, we allow our globals to exist,
|
||||
but instead of accessing them in a foolish way, we accept them as parameters.
|
||||
</p>
|
||||
<p>Example 1:</p>
|
||||
<pre>
|
||||
<code lang="java">
|
||||
public void saveUser(User u) {
|
||||
// Where did this guy come from? Idk, it's probably defined in some XML file somewhere :)
|
||||
DatabaseHandler dbh = GlobalContextHolder.getContext("database");
|
||||
dbh.table("users").save(u);
|
||||
}
|
||||
|
||||
// Main.java
|
||||
public static void main(String[] args) {
|
||||
User user = new User("Bob", 23);
|
||||
saveUser(user);
|
||||
}
|
||||
</code>
|
||||
</pre>
|
||||
<p>Example 2:</p>
|
||||
<pre>
|
||||
<code lang="java">
|
||||
// Database.java
|
||||
private static DatabaseHandler DBH;
|
||||
|
||||
public static DatabaseHandler getDatabase() {
|
||||
if (DBH == null) {
|
||||
DBH = DatabaseHandler.newConnection("mysql://foo@bar:foo.com:3306");
|
||||
}
|
||||
|
||||
return DBH;
|
||||
}
|
||||
|
||||
// Main.java
|
||||
public static void saveUser(User u, DatabaseHandler dbh) {
|
||||
dbh.table("users").save(u);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Database.initialize();
|
||||
User user = new User("Bob", 23);
|
||||
saveUser(user, Database.get());
|
||||
}
|
||||
</code>
|
||||
</pre>
|
||||
<p>
|
||||
Overall, this drastically reduces the mental overhead of the system, allowing for simple unit-testing (if you want), and
|
||||
a simplistic approach to scaling, since you don't have to worry about costly abstractions that don't actually simplify anything.
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
20
index.css
Normal file
@@ -0,0 +1,20 @@
|
||||
:root {
|
||||
--fg: #222;
|
||||
--link-fg: #116630;
|
||||
}
|
||||
|
||||
body {
|
||||
color: var(--fg);
|
||||
font-family: georgia, serif;
|
||||
font-size: medium;
|
||||
max-width: 40em;
|
||||
margin: 0 auto;
|
||||
padding: 0 1em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--link-fg);
|
||||
text-decoration: none;
|
||||
text-decoration-line: underline;
|
||||
text-decoration-style: dashed;
|
||||
}
|
||||
59
index.html
@@ -4,71 +4,49 @@
|
||||
<title>rawley.xyz</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="description" value="Rawley Fowler's personal website, about Perl, Emacs and Software in General.">
|
||||
<link rel="stylesheet" href="index.css">
|
||||
</head>
|
||||
<body style="margin: 0; padding: 0; background-color: rgb(254, 249, 232)">
|
||||
<div style="margin: 48px; width: 530px;">
|
||||
<pre>
|
||||
<code>
|
||||
, ,
|
||||
/( )`
|
||||
\ \___ / |
|
||||
/- _ `-/ '
|
||||
(/\/ \ \ /\
|
||||
/ / | ` \
|
||||
O O ) / |
|
||||
`-^--'`< '
|
||||
(_.) _ ) /
|
||||
`.___/` /
|
||||
`-----' /
|
||||
<----. __ / __ \
|
||||
<----|====O)))==) \) /====
|
||||
<----' `--' `.__,' \
|
||||
| |
|
||||
\ /
|
||||
______( (_ / \______
|
||||
,' ,-----' | \
|
||||
`--{__________) \/
|
||||
</code>
|
||||
</pre>
|
||||
<body>
|
||||
<div>
|
||||
<p>
|
||||
Hi, I'm Rawley a Christian, Husband, Dad, Emacs evangelist and BSD user.
|
||||
Hi, I'm Rawley. I'm a full-time Husband, Dad, Emacs evangelist and Perl aficionado.
|
||||
</p>
|
||||
<p>
|
||||
I am the creator of many <a href="https://www.gnu.org/philosophy/free-sw.en.html">free-software</a> libraries and tools.
|
||||
I have extensive knowledge of Perl, Java, the JVM, and Functional Programming. I'm always working on something, whether it be my
|
||||
I have extensive knowledge of Perl, Java, JVM, and Functional Programming. I'm always working on something, whether it be my
|
||||
100 year old house, or some 100 year old code. I'm always looking for fun things to work on.
|
||||
</p>
|
||||
<h2>Sitemap</h2>
|
||||
<h2>Blog Posts</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="/niche-software.html">Using a niche programming language</a>
|
||||
<a href="/posts/niche-software.html">Using a niche programming language</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/dancer2-controllers.html">Dancer2::Controllers and Perl Attributes</a>
|
||||
<a href="/posts/dancer2-controllers.html">Dancer2::Controllers and Perl Attributes</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/perl-oo-action-benchmark.html">Perl OO benchmarks</a>
|
||||
<a href="/posts/perl-oo-action-benchmark.html">Perl OO benchmarks</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/maybe-escaping-evil.html">Exploring <code>evil-mode</code> alternatives</a>
|
||||
<a href="/posts/maybe-escaping-evil.html">Exploring <code>evil-mode</code> alternatives</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/in-defense-of-global-variables.html">How to Properly use Global Variables</a>
|
||||
<a href="/posts/in-defense-of-global-variables.html">How to Properly use Global Variables</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/2024.html">2024</a>
|
||||
<a href="/posts/2024.html">2024</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/jpa-hibernate-stupid-performance.html">Making JPA Repository stupid fast with Entity Graph</a>
|
||||
<a href="/posts/jpa-hibernate-stupid-performance.html">Making JPA Repository stupid fast with Entity Graph</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/docker-mod-perl.html">Running Mojolicious with <code>mod_perl</code> in Docker</a>
|
||||
<a href="/posts/docker-mod-perl.html">Running Mojolicious with <code>mod_perl</code> in Docker</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/emacs.html">Emacs</a>
|
||||
<a href="/posts/emacs.html">Emacs</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/become-an-engineer.html">The real software path</a>
|
||||
<a href="/posts/become-an-engineer.html">The real software path</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h2>Projects</h2>
|
||||
@@ -89,12 +67,13 @@
|
||||
<a href="https://github.com/rawleyfowler/distribution-builder-cmake">Distribution::Builder::Cmake</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h2></h2>
|
||||
<div>
|
||||
<a href="http://www.gnu.org/software/emacs">
|
||||
<img src="gnu_emacs.png"/>
|
||||
<img src="/assets/gnu_emacs.png"/>
|
||||
</a>
|
||||
<a href="https://openbsd.org">
|
||||
<img src="openbsd.gif" style="width: 120px; height 80px" />
|
||||
<img src="/assets/openbsd.gif" style="width: 120px; height 80px" />
|
||||
</a>
|
||||
</div>
|
||||
<h2>Disclaimer</h2>
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Achieving Stupid Performance with JPA and Hibernate</title>
|
||||
<meta name="description" value="Making JPA and Hibernate break the sound barrier on a ridiculous data set.">
|
||||
</head>
|
||||
<body style="margin: 0; padding: 0; background-color: rgb(254, 249, 232)">
|
||||
<div style="margin: 48px; width: 580px;">
|
||||
<a href="/"><< back</a>
|
||||
<h1 id="jpa-is-slow">JPA is slow, lets make it stupid fast</h1>
|
||||
<p>
|
||||
JPA is <b>not</b> performant. Mainly because of things like batching, and this incessant idea that
|
||||
querying relationships lazily is somehow fast, its literally just deferring the work, which makes sense
|
||||
if you potentially don't want to use the data, but most people want that data anyways, or serialize it.
|
||||
</p>
|
||||
<p>
|
||||
I experienced this recently with a massive data set, this database was 1 core table of 4 million rows, followed by multiple child One-To-Many table
|
||||
of close to 10 million rows, and a single One-to-One with ~4 million rows as well. To use the service built on top of this massive data, you had to search
|
||||
with JPA search specifications, which turns out also to be insanely slow. The benchmark starts us at 15 or so minutes, which is obviously unacceptable.
|
||||
</p>
|
||||
<h2 id="go-fast">Time to go fast</h2>
|
||||
<p>
|
||||
By enabling <pre><code>logging.level.org.hibernate.SQL=DEBUG</code></pre> and <pre><code>logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE</code></pre>
|
||||
you're able to see the ridiculous number queries JPA is executing, they're un-countable, there's so many!! How can we fix this?
|
||||
</p>
|
||||
<p>
|
||||
If you're thinking of using <code>@Batch(100)</code>, it could work, only issue is JPA will batch each relationship, so each of our tables will still require
|
||||
<code>n/100</code> calls where <code>n</code> is the number of rows with relationships. So theoretically a 100x speed bump right? Well, it's actually more
|
||||
like a 33x performance bump, since you still have the overhead of making the database connections, and need to get a lock every time you select. Doing this we moved to around
|
||||
3-5 minutes depending on load per large call. This however, was still unacceptable.
|
||||
</p>
|
||||
<p>
|
||||
What if instead we just forced JPA to use <code>OUTER JOIN</code>? Isn't that exactly what the ANSI SQL wizards would tell you to do?
|
||||
Obviously, this is the solution, one single connection, 1 lock, and let the B-Tree optimizations inside of the database handle all of this ugliness for us.
|
||||
To do this you need to use something called <a href="https://www.baeldung.com/jpa-entity-graph"><code>@EntityGraph</code></a>
|
||||
on your JPA repository, what this does is forces JPA to use a <code>OUTER JOIN</code>
|
||||
to join relationships. This even works on nested entities, say I have Entity A with a child B which also has a One-to-Many on C, all you need to do
|
||||
is add the relationship to the entity graph with the <code>@NamedEntityGraph</code> annotation, then provide it with a few nice args like name,
|
||||
and attributeNodes which will point to your sub entity. Then finally on your JPA repository call you stitch the entity graph back together.
|
||||
</p>
|
||||
<pre>
|
||||
<code>
|
||||
@Repository
|
||||
public interface ARepository extends JpaRepository<A, UUID>, JpaSpecificationExecutor<A> {
|
||||
@Override
|
||||
@EntityGraph(attributePaths = { "bs", "B.cs" }) // Where B's are children of A's, and C's are children of B's.
|
||||
Page<A> findAll(@Nullable Specification<A> specification, Pageable pageable);
|
||||
}
|
||||
</code>
|
||||
</pre>
|
||||
<p>
|
||||
After applying these, the query time went down from 15 minutes to ... *drum-roll* ... 3 seconds. So please, for the love of all that is computationally efficient, force your JPA
|
||||
to use <code>OUTER JOIN</code>, or even roll your own SQL, ORM's really are one of the biggest trade-offs, and they really can bite you. This is why tend to
|
||||
stay in the <code>DBI</code> universe when I write Perl. It's funny shocking Ruby on Rails and Java developers with my ~15ms queries :D
|
||||
</p>
|
||||
<br>
|
||||
<br>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,48 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Escaping evil-mode, maybe?</title>
|
||||
<meta name="description" content="Trying to escape evil mode">
|
||||
<meta name="keywords" content="Emacs, Perl, Vim, evil-mode escape">
|
||||
<meta charset="UTF-8">
|
||||
</head>
|
||||
<body style="margin: 0; padding: 0; background-color: rgb(254, 249, 232)">
|
||||
<div style="margin: 48px; width: 530px;">
|
||||
<a href="/"><< back</a>
|
||||
<h1 id="escaping-evil">Escaping evil-mode</h1>
|
||||
<p>
|
||||
I've been using <a href="https://www.emacswiki.org/emacs/Evil"><code>evil-mode</code></a> for almost 4 years at this point, and Vim keybinds even longer.
|
||||
However, I think it's almost time for me to change. In 2022 I spent the later half of the year just on default, vanilla emacs keybinds.
|
||||
This was really enjoyable and let me learn more about how the puritans do Emacs, but in general,
|
||||
I just felt a lot slower. So I came back to <code>evil-mode</code>, and have been using it daily ever since.
|
||||
But with some recent annoyances in Evil, and having to almost double my config size to use Evil integrations with other packages,
|
||||
I've been thinking of using Vanilla again, or exploring some of the other modal plugins like: <a href="https://github.com/meow-edit/meow">meow</a>,
|
||||
<a href="https://github.com/xahlee/xah-fly-keys">Xah-Fly-Keys</a>, or <a href="https://github.com/emacsorphanage/god-mode">god-mode</a> (don't love the name of this one :P).
|
||||
So, to the disdain of my productivity, I am going to try to use each of these for a week at a time, and report back each week with an update.
|
||||
</p>
|
||||
<h2 id="the-test">The test</h2>
|
||||
<p>
|
||||
I will be comparing each mode on the following all scored out of 10:
|
||||
<ul>
|
||||
<li>Learnability. How long does it take for a seasoned Vim and Emacs user to learn?</li>
|
||||
<li>
|
||||
Feel. How ergonomic, and how fast does it "feel"? This is fairly subjective but it does matter to me.
|
||||
I like to feel like i'm hacking on a 80's mainframe, with a nuclear threat on the horizon.
|
||||
</li>
|
||||
<li>Config. How difficult is it to configure, and get working with other packages</li>
|
||||
</ul>
|
||||
</p>
|
||||
<h2 id="evil-review"><code>evil-mode</code>'s rating</h2>
|
||||
<p>
|
||||
Here is my review of <code>evil-mode</code>:
|
||||
<ul>
|
||||
<li>Learnability: 10 it's just Vim's keybinds (mostly)</li>
|
||||
<li>Feel: 7 it does feel fast, and fairly ergonomic, but the use of escape to escape modes kind of sucks</li>
|
||||
<li>Config: 3 you have to install extra packages for almost everything you could think of to add evil support</li>
|
||||
</ul>
|
||||
Overall I do like <code>evil-mode</code>, and i'm very productive with it, but I find that a lot of little issues pop-up on a day to day basis
|
||||
that could be ironed out. Things like not having re-do automatically working. At the end of the day I use Emacs for both, speed, but also,
|
||||
for extensability, something that I think <code>evil-mode</code> restricts.
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,45 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Using Niche Programming Languages</title>
|
||||
<meta name="description" value="How using Niche Programming Languages can drastically improve your hiring candidates, and in-turn your products">
|
||||
</head>
|
||||
<body style="margin: 0; padding: 0; background-color: rgb(254, 249, 232)">
|
||||
<div style="margin: 48px; width: 580px;">
|
||||
<a href="/"><< back</a>
|
||||
<p>Published March 7th, 2024</p>
|
||||
<h1>Using Niche Programming Languages</h1>
|
||||
<p>
|
||||
Earlier this week,
|
||||
<a href="https://bleacherreport.com">Bleacher Report</a>
|
||||
was bought out and forced to re-write their Elixir/Erlang backend in something "more-mainstream" by the
|
||||
buying party (Warner), this is a HUGE mistake, and an example of how main-stream thought has eroded the foundations of software engineering. Bleacher Report had used
|
||||
Elixir/Erlang since at least <a href="https://www.erlang-solutions.com/case-studies/bleacher-report-case-study/">2017</a>,
|
||||
when their case-study of going from 150 servers to 5 via converting their Ruby code to Elixir/Erlang was published.
|
||||
All of this resliency, and engineering effort is now going to be rewritten in none other than JavaScript, which of course will be a tremedous effort.
|
||||
</p>
|
||||
<p>
|
||||
So why did they do it? Well, they had lay-offs, and then they needed to re-fill the seats they laid off a few years later. Instead of leveraging this "gold card"
|
||||
that is a niche language, Warner decides that it will be too hard to fill N seats. Which is also another issue in the software world, the "butts in seats typing"
|
||||
phalacy that more will get done. Anyways, what Warner could have done, is use this fantastical power bestowed by a niche language, and got the best developers
|
||||
in that niche technology. If they hired 15 Node devs for 100k a year each, they could afford 5 Erlang masterminds for 300k a year each (and then you wouldn't need a
|
||||
rewrite!) The other option is to hire a few Erlang devs and have them train other devs which could be an effective cost-cutting measure as well, without
|
||||
having to rewrite your codebase.
|
||||
</p>
|
||||
<p>
|
||||
I've been asked many times by developers, "should I learn X, it's so niche but it looks cool", and to every single one of those questions, I shout "YES!!!".
|
||||
Learning is <u>ALWAYS</u> good. But also, if you get really good at these niche technologies, you can become a SME (subject matter expert), and get hired
|
||||
by a business looking for people like you. Jane Street is notorious for using OCaml for literally everything. Yaron Minsky, mentions at Jane Street states
|
||||
that while there aren't many OCaml developers, the small set that does exist is typically <u>really good</u>, and a grade above the usual Python, Java, JavaScript developer
|
||||
(you'll choke on your coffee when you read Jane Streets developer salaries as well).
|
||||
</p>
|
||||
<p>
|
||||
When starting a new project I think you should consider using a niche language.
|
||||
You learn a lot, but also when it comes time to scale your idea, and you need to hire a partner or two,
|
||||
you'll be greatful you chose it, when extremely talented and passionate individuals send you their resume solely because you chose a backend written in Haskell, Scala,
|
||||
Perl, OCaml, Elixir, Clojure, Lua, etc. This is what happened for NoRedInk, after writing their original MVP in Ruby, they ended up using Haskell and Elm for new
|
||||
services, and now, they're one of the most well known Functional Programming shops, and they've managed to hire some brilliant people, like the creator of Elm himself!
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
47
normalize_html.pl
Normal file
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
use 5.036;
|
||||
|
||||
use FindBin;
|
||||
use File::Find;
|
||||
use File::Slurp;
|
||||
use XML::LibXML;
|
||||
|
||||
find(
|
||||
sub {
|
||||
return unless $_ =~ /.*.html$/xmi;
|
||||
say "Processing: $_";
|
||||
my $loc = "$FindBin::Bin/posts/$_";
|
||||
my $html = read_file($loc);
|
||||
my $doc = XML::LibXML->new->parse_html_string($html);
|
||||
|
||||
my ($html_tag) = $doc->getElementsByTagName('html');
|
||||
$html_tag->setAttribute( lang => 'en' );
|
||||
|
||||
my @meta_tags = $doc->getElementsByTagName('meta');
|
||||
|
||||
for my $meta (@meta_tags) {
|
||||
if ( my $v = $meta->getAttribute('value') ) {
|
||||
$meta->removeAttribute('value');
|
||||
$meta->setAttribute( content => $v );
|
||||
}
|
||||
}
|
||||
|
||||
my @links = $doc->getElementsByTagName('link');
|
||||
|
||||
for my $link (@links) {
|
||||
if ( $link->getAttribute('href') eq '/index.css' ) {
|
||||
say "Already done $_";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
my $st = XML::LibXML::Element->new('link');
|
||||
$st->setAttribute( rel => 'stylesheet' );
|
||||
$st->setAttribute( href => '/index.css' );
|
||||
my ($head) = $doc->getElementsByTagName('head');
|
||||
$head->appendChild($st);
|
||||
write_file( $loc, $doc->toString() );
|
||||
},
|
||||
"$FindBin::Bin/posts"
|
||||
);
|
||||
@@ -1,559 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Perl OO benchmarking</title>
|
||||
<meta name="description" value="Perl object-orientation performance benchmarks between Moose, Moo, Modules, Corinna with a cross-language comparison against Ruby and Raku (Perl 6)">
|
||||
</head>
|
||||
<body style="margin: 0; padding: 0; background-color: rgb(254, 249, 232)">
|
||||
<div style="margin: 48px; width: 580px;">
|
||||
<a href="/"><< back</a>
|
||||
<h1>Perl OO benchmarking</h1>
|
||||
<p>
|
||||
I've spent a lot of time working in projects that use the <a href="https://en.wikipedia.org/wiki/Command_pattern"><code>Action pattern</code></a> (also called the <code>Command pattern</code>).
|
||||
Now, regardless of how i've land on OO vs Functional in the last 5 years, there has always been a question I have yet to answer: "How much does this abstraction cost,
|
||||
and more importantly, how much does object instantiation actually cost?" (since the action pattern has you instantiating A LOT of objects)
|
||||
</p>
|
||||
<p>
|
||||
So I set out to benchmark, Perl OO, using the traditional Module OO, <code>Corinna</code>, <code>Moo</code> and <code>Moose</code>. But I thought it may also
|
||||
provide some value to compare these findings to other languages, namely ones in the same sort of realm that Perl has lives in: <code>Ruby</code> and <code>Raku (formerly Perl 6)</code>.
|
||||
</p>
|
||||
<h2 id="theBenchmark">The benchmark</h2>
|
||||
<p>
|
||||
The benchmark is fairly simple, since the goal here is to test the actual instantiation costs, so the method associated with the implemented action is very simple.
|
||||
An <code>Action</code> object has two members, <code>name</code> and <code>age</code>. It's <code>execute</code> method returns a Map/Hash/Dictionary, with the following keys
|
||||
<code>{ name => self.name, age => self.age }</code>. Basically just accessing the instantiated objects <code>age</code> and <code>name</code> attributes, and associating them to
|
||||
keys of the same name.
|
||||
</p>
|
||||
<p>
|
||||
One-million <code>Action</code> objects will be instantiated in a O(n) loop, and executed, then destroyed all within the same scope. Like so:
|
||||
</p>
|
||||
<pre>
|
||||
<code>
|
||||
my $name = 'Tim';
|
||||
my $age = 12;
|
||||
for ( 1 .. 1000000 ) {
|
||||
my $user = Action->new( name => $name, age => $age )->execute();
|
||||
}
|
||||
</code>
|
||||
</pre>
|
||||
<p>
|
||||
This will be performed one-hundred times, then, the average of the times taken to do the one-million iterations will be the benchmark result.
|
||||
It is also important to note that the initial load-time of the language run-times is included in the calculation, though they are mostly negligble especially
|
||||
in the Perl case, and the actual instantiation takes the vast-majority of the time (close to 99% on average).
|
||||
</p>
|
||||
<p>
|
||||
This benchmark was performed on an Intel i7 12700KF, using DDR5 memory.
|
||||
</p>
|
||||
<h3>Summary Table</h3>
|
||||
<table style="border: 1px solid black;">
|
||||
<tr>
|
||||
<th style="text-align: left;">Language</th>
|
||||
<th style="text-align: left;">Performance</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
Perl Module OO
|
||||
</td>
|
||||
<td>
|
||||
454.627ms
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Perl Module OO + Types
|
||||
</td>
|
||||
<td>
|
||||
505.276ms
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Corinna</td>
|
||||
<td>564.411ms</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Moo
|
||||
</td>
|
||||
<td>
|
||||
960.03ms
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Moo + Types
|
||||
</td>
|
||||
<td>
|
||||
2308.226ms
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Moose
|
||||
</td>
|
||||
<td>
|
||||
11420.455ms
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Moose + Immutable</td>
|
||||
<td>1182.109ms</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Moose + Types
|
||||
</td>
|
||||
<td>
|
||||
13649.37ms
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ruby</td>
|
||||
<td>167.627ms</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Raku (MoarVM start-up subtracted)</td>
|
||||
<td>801.947ms</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h2 id="timesAndImplementations">Times and implementations</h2>
|
||||
<h3 id="perlImpls">Perl</h3>
|
||||
<h4 id="perlModuleOO">Module OO</h4>
|
||||
<p>
|
||||
Using the traditional Perl approach to OO using ref's and modules, is by far the fastest.
|
||||
</p>
|
||||
<h5>Code:</h5>
|
||||
<pre>
|
||||
<code>
|
||||
package Action;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
sub execute {
|
||||
my $self = shift;
|
||||
return +{ name => $self->{name}, age => $self->{age} };
|
||||
}
|
||||
|
||||
sub new {
|
||||
my ( $class, $name, $age ) = @_;
|
||||
my $self = { name => $name, age => $age };
|
||||
return bless $self, $class;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
package main;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my $name = 'Tim';
|
||||
my $age = 12;
|
||||
for ( 1 .. 1000000 ) {
|
||||
my $user = Action->new( $name, $age )->execute();
|
||||
}
|
||||
</code>
|
||||
</pre>
|
||||
<p>
|
||||
This implementation is alright, it's fast, but it doesn't provide any validations, which is what I assume most OO frameworks like <code>Moo</code> and <code>Moose</code> do, especially
|
||||
if you use modules like <code>Type::Tiny</code>.
|
||||
</p>
|
||||
<h5>Time:</h5>
|
||||
<pre>
|
||||
<code>
|
||||
PERL TIME : 454.627ms
|
||||
</code>
|
||||
</pre>
|
||||
<h4 id="perlModuleOOTypes">Module OO with some type checks</h4>
|
||||
<p>
|
||||
Considering my assumptions about other OO libraries I decided to add a few checks to the Module OO implementation,
|
||||
using <code>Scalar::Util</code> we can test if <code>age</code> is a number, and also ensure the defined-ness of our
|
||||
attributes using the built-in <code>defined</code>.
|
||||
</p>
|
||||
<pre>
|
||||
<code>
|
||||
package Action;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Scalar::Util qw(looks_like_number);
|
||||
|
||||
sub execute {
|
||||
my $self = shift;
|
||||
return +{ name => $self->{name}, age => $self->{age} };
|
||||
}
|
||||
|
||||
sub new {
|
||||
my ( $class, $name, $age ) = @_;
|
||||
|
||||
if ( !defined $name || !defined $age ) {
|
||||
die 'name and age, should be defined.';
|
||||
}
|
||||
|
||||
if ( !looks_like_number($age) ) {
|
||||
die 'age should be a number.';
|
||||
}
|
||||
|
||||
my $self = { name => $name, age => $age };
|
||||
return bless $self, $class;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
package main;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my $name = 'Tim';
|
||||
my $age = 12;
|
||||
for ( 1 .. 1000000 ) {
|
||||
my $user = Action->new( $name, $age )->execute();
|
||||
}
|
||||
</code>
|
||||
</pre>
|
||||
<p>This only came at a net-cost of around 50ms extra on average, which is surprisingly fast.</p>
|
||||
<pre>
|
||||
<code>
|
||||
PERL + TYPES TIME : 505.276ms
|
||||
</code>
|
||||
</pre>
|
||||
<h5>Code:</h5>
|
||||
<h4 id="perlCorinnaModuleOO">Corinna</h4>
|
||||
<p>
|
||||
Corinna is a new OO system added to Perl 5.38 but still marked as experimental. It performs very well compared to the features it provides,
|
||||
but it is definitely not something you'll see in the wild too often.
|
||||
</p>
|
||||
<pre>
|
||||
<code>
|
||||
use feature 'class';
|
||||
no warnings;
|
||||
|
||||
class Action {
|
||||
field $name : param;
|
||||
field $age : param;
|
||||
|
||||
method execute () {
|
||||
return +{ name => $name, age => $age };
|
||||
}
|
||||
}
|
||||
|
||||
my $name = 'Tim';
|
||||
my $age = 12;
|
||||
for ( 1 .. 1000000 ) {
|
||||
Action->new( name => $name, age => $age )->execute();
|
||||
}
|
||||
</code>
|
||||
</pre>
|
||||
<p>
|
||||
I had to disable warnings on this because I wasn't sure what flags I needed to set in the <code>feature</code> or the <code>experimental</code>,
|
||||
also the lack of documentation definitely hurt, it took me a while to figure out I had to <code>use feature 'class';</code>. For some reason I thought
|
||||
the feature flag was <code>corinna</code> or something.
|
||||
</p>
|
||||
<h5>Time:</h5>
|
||||
<pre>
|
||||
<code>
|
||||
CORINNA TIME : 564.411ms
|
||||
</code>
|
||||
</pre>
|
||||
<h4 id="perlMoo">Moo</h4>
|
||||
<p>
|
||||
<code>Moo</code> is a "Minimalist Object Orientation" for Perl. It's what I've used the most, and it performs quite well for all of the
|
||||
features it gives you. However, there is definitely a cost, one that a lot of developers ignore. I've done two implementations here, one with
|
||||
<code>Type::Tiny</code>, which adds optional type-checking to attributes, and one without. The difference was quite compelling!
|
||||
</p>
|
||||
<h5>Code:</h5>
|
||||
Without <code>Type::Tiny</code>:
|
||||
<pre>
|
||||
<code>
|
||||
package Action;
|
||||
|
||||
use Moo;
|
||||
use namespace::clean;
|
||||
|
||||
has name => (
|
||||
is => 'ro',
|
||||
required => 1
|
||||
);
|
||||
|
||||
has age => (
|
||||
is => 'ro',
|
||||
required => 1
|
||||
);
|
||||
|
||||
sub execute {
|
||||
my $self = shift;
|
||||
return +{ name => $self->name, age => $self->age };
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
package main;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my $name = 'Tim';
|
||||
my $age = 12;
|
||||
for ( 1 .. 1000000 ) {
|
||||
my $user = Action->new( name => $name, age => $age )->execute();
|
||||
}
|
||||
</code>
|
||||
</pre>
|
||||
With <code>Type::Tiny</code>:
|
||||
<pre>
|
||||
<code>
|
||||
package Action;
|
||||
|
||||
use Moo;
|
||||
use Types::Standard qw(Int Str);
|
||||
use namespace::clean;
|
||||
|
||||
has name => (
|
||||
is => 'ro',
|
||||
isa => Str,
|
||||
required => 1
|
||||
);
|
||||
|
||||
has age => (
|
||||
is => 'ro',
|
||||
isa => Int,
|
||||
required => 1
|
||||
);
|
||||
|
||||
sub execute {
|
||||
my $self = shift;
|
||||
return +{ name => $self->name, age => $self->age };
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
package main;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my $name = 'Tim';
|
||||
my $age = 12;
|
||||
for ( 1 .. 1000000 ) {
|
||||
my $user = Action->new( name => $name, age => $age )->execute();
|
||||
}
|
||||
</code>
|
||||
</pre>
|
||||
<p>
|
||||
To my shock, <code>Type::Tiny</code> degrades performance by close to 300%. However, the more I looked into <code>Type::Tiny</code>, the more it made sense.
|
||||
<code>Type::Tiny</code>, to enforce types uses a lot of complex meta-programming, and ref checks, that add up to a ton of extra operations. Perhaps it would be
|
||||
worth using <code>B::Concise</code> or <code>B::Deparse</code> to see how many more operations this actually adds, but thats something for another day.
|
||||
</p>
|
||||
<h5>Time:</h5>
|
||||
<pre>
|
||||
<code>
|
||||
MOO TIME : 960.03ms
|
||||
MOO + TYPES TIME : 2308.226ms
|
||||
</code>
|
||||
</pre>
|
||||
<h4 id="perlMoose">Moose</h4>
|
||||
<p>
|
||||
<code>Moose</code> is a heavyweight, industrial purpose OO framework for Perl, at which <code>Moo</code> derives from. It is big, and heavy, and unfortunately,
|
||||
really slow for tasks like this. After starting this benchmark, I thought that the slowness was coming from loading the module between runs, but after timing the average load time,
|
||||
the time spent was negligble (31ms at most).
|
||||
</p>
|
||||
<p>
|
||||
Like in the <code>Moo</code> benchmark, I did two implementations, one using <code>Type::Tiny</code>, and one not.
|
||||
</p>
|
||||
<h5>Code:</h5>
|
||||
<pre>
|
||||
<code>
|
||||
package Action;
|
||||
|
||||
use Moose;
|
||||
use namespace::clean;
|
||||
|
||||
has name => (
|
||||
is => 'ro',
|
||||
required => 1
|
||||
);
|
||||
|
||||
has age => (
|
||||
is => 'ro',
|
||||
required => 1
|
||||
);
|
||||
|
||||
sub execute {
|
||||
my $self = shift;
|
||||
return +{ name => $self->name, age => $self->age };
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
package main;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my $name = 'Tim';
|
||||
my $age = 12;
|
||||
for ( 1 .. 1000000 ) {
|
||||
my $user = Action->new( name => $name, age => $age )->execute();
|
||||
}
|
||||
</code>
|
||||
</pre>
|
||||
With <code>Type::Tiny</code>:
|
||||
<pre>
|
||||
<code>
|
||||
package Action;
|
||||
|
||||
use Moose;
|
||||
use Types::Standard qw(Int Str);
|
||||
use namespace::clean;
|
||||
|
||||
has name => (
|
||||
is => 'ro',
|
||||
isa => Str,
|
||||
required => 1
|
||||
);
|
||||
|
||||
has age => (
|
||||
is => 'ro',
|
||||
isa => Int,
|
||||
required => 1
|
||||
);
|
||||
|
||||
sub execute {
|
||||
my $self = shift;
|
||||
return +{ name => $self->name, age => $self->age };
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
package main;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my $name = 'Tim';
|
||||
my $age = 12;
|
||||
for ( 1 .. 1000000 ) {
|
||||
my $user = Action->new( name => $name, age => $age )->execute();
|
||||
}
|
||||
</code>
|
||||
</pre>
|
||||
<p>
|
||||
Just like <code>Moo</code> with types, <code>Type::Tiny</code> hits the final <code>Moose</code> result by around 2000ms overall.
|
||||
</p>
|
||||
<p>
|
||||
<b>Amendment</b>: After publishing my original findings I was alerted to a <a href="https://github.com/rawleyfowler/perl-oo-action-benchmark/pull/1">setting you could apply to Moose classes</a> that make them immutable.
|
||||
Immutable often means faster in-terms of creation but slower in terms of manipulation, but since this workload spends most of its time creating, and none of its time editing,
|
||||
this produced an incredible 10x speed improvement.
|
||||
</p>
|
||||
<h5>Immutable trick for Moose</h5>
|
||||
<pre>
|
||||
<code>
|
||||
__PACKAGE__->meta->make_immutable;
|
||||
</code>
|
||||
</pre>
|
||||
<h5>Time:</h5>
|
||||
<pre>
|
||||
<code>
|
||||
MOOSE TIME : 11420.455ms
|
||||
MOOSE + TYPES TIME : 13649.37ms
|
||||
MOOSE IMMU TIME : 1182.109ms
|
||||
</code>
|
||||
</pre>
|
||||
<h3 id="rubyImpl">Ruby</h3>
|
||||
<p>
|
||||
I also did a quick Ruby implementation, since its a "true" Object-Oriented language, I assumed it would have
|
||||
a lot of optimizations built-in for this sort of work, and based on its runtime, that seems to be the case.
|
||||
</p>
|
||||
<p>
|
||||
Also, note, this was on Ruby 3.1.2, not Ruby 3.3 with YJIT, so this could theoretically be faster.
|
||||
</p>
|
||||
<h5>Code:</h5>
|
||||
<pre>
|
||||
<code>
|
||||
class Action
|
||||
def initialize(age, name)
|
||||
@age = age
|
||||
@name = name
|
||||
end
|
||||
|
||||
def execute
|
||||
{ name: @name, age: @age }
|
||||
end
|
||||
end
|
||||
|
||||
age = 12
|
||||
name = 'Tim'
|
||||
1000000.times do
|
||||
user = Action.new(age, name).execute()
|
||||
end
|
||||
</code>
|
||||
</pre>
|
||||
<h5>Time:</h5>
|
||||
<pre>
|
||||
<code>
|
||||
RUBY TIME : 167.627ms
|
||||
</code>
|
||||
</pre>
|
||||
<h3 id="rakuImpl">Raku (formerly Perl 6)</h3>
|
||||
<p>
|
||||
Finally, we have Raku, which unfortunately doesn't do too well. To make this a little more competitive,
|
||||
I subtracted the run-time of MoarVM from the end-result. Though, I think Raku's implementation is the simplest to
|
||||
understand in terms of langauge design, so it gets a +1 from me for that.
|
||||
</p>
|
||||
<h5>Code:</h5>
|
||||
<pre>
|
||||
<code>
|
||||
class Action {
|
||||
has $.name;
|
||||
has $.age;
|
||||
|
||||
method execute {
|
||||
return %(name => $!name, age => $!age);
|
||||
}
|
||||
}
|
||||
|
||||
my $name = 'Tim';
|
||||
my $age = 12;
|
||||
for 1..1000000 -> $ {
|
||||
my $user = Action.new(name => $name, age => $age).execute();
|
||||
}
|
||||
|
||||
</code>
|
||||
</pre>
|
||||
<h5>Time (with MoarVM startup time removed):</h5>
|
||||
<pre>
|
||||
<code>
|
||||
RAKU TIME : 801.947ms
|
||||
</code>
|
||||
</pre>
|
||||
<h2>So what?</h2>
|
||||
<p>
|
||||
Object instantiation has a cost. A lot of people ignore this, especially when using heavyweight libraries like <code>Moose</code>.
|
||||
You can put this into practical terms simply, using basic Perl module OO you effectively double the number of objects of this type you can create and execute a
|
||||
method on given any time-frame compared to <code>Moo</code> without types, and twenty-two times more objects versus <code>Moose</code> without types.
|
||||
But these abstractions exist for reasons, and they are used for a reason.
|
||||
</p>
|
||||
<p>
|
||||
<code>Moo</code> and <code>Moose</code> have their places, especially in web-applications where the number of instantiations is low, and the expensive
|
||||
operations happen during side-effects like database operations.
|
||||
This also goes without mentioning some of the great features modules like <code>Moo</code> and <code>Moose</code> provide.
|
||||
It is valuable to know that if you need something to perform well, <code>Moo</code> and <code>Moose</code>
|
||||
may incur overhead you hadn't previously considered. This is compounded when enforcing types.
|
||||
For hot-code that will be hit repeatedly within a short amount of time, this can drastically effect performance, think of things like a landing page, or a search-bar API.
|
||||
</p>
|
||||
<p>
|
||||
<code>Corinna</code>, is a very nice prospect, it offers a lot of great things from <code>Moo</code> and <code>Moose</code> but seems to
|
||||
exalt far less of a performance penalty. It will definitely be on my radar in the future, especially when the documentation improves.
|
||||
</p>
|
||||
<p>
|
||||
Another approach is to simply use functions, which of course will perform the best. But, it's hard to argue to do this unless performance is the number one goal,
|
||||
especially on codebases that follow this pattern.
|
||||
</p>
|
||||
<div>
|
||||
You can view the <a href="https://github.com/rawleyfowler/perl-oo-action-benchmark">Source code</a>.
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,17 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Using LiteXL!</title>
|
||||
<meta name="description" content="Trying Lite XL, my thoughts on the Lite XL text editor">
|
||||
<meta name="keywords" content="Lite-XL text-editor text editor perl emacs">
|
||||
<meta charset="UTF-8">
|
||||
</head>
|
||||
<body style="margin: 0; padding: 0; background-color: rgb(254, 249, 232)">
|
||||
<div style="margin: 48px; width: 530px;">
|
||||
<a href="/"><< back</a>
|
||||
<h1 id="trying-lite-xl">Trying Lite-XL</h1>
|
||||
<p>
|
||||
<!-- TODO: Write about why I like and dislike Lite-XL -->
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||