reworkify

This commit is contained in:
ivan
2025-04-07 23:58:16 -05:00
parent de6cd11794
commit 447c07a046
19 changed files with 87 additions and 1287 deletions

View File

@@ -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="/">&lt;&lt; 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>

View File

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View File

@@ -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="/">&lt;&lt; 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>

View File

@@ -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="/">&lt;&lt; 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_&lt;reftype&gt;_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 =&gt; /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 =&gt; /home) {
my $app = shift;
my $user_name = $app-&gt;session('user');
return "Welcome back $user_name!";
}
sub home_page : Route(post =&gt; /login) {
my $app = shift;
my $password = $app-&gt;body_parameters-&gt;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>

View File

@@ -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="/">&lt;&lt; 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> &gt; 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>' &gt;&gt; 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> =&gt; <span class="hljs-function"><span class="hljs-keyword">sub</span> </span>{
<span class="hljs-keyword">shift</span>-&gt;render( <span class="hljs-string">text =&gt;</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-&gt;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">&lt;VirtualHost *:80&gt;</span>
<span class="hljs-section">&lt;Location /&gt;</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">&lt;/Location&gt;</span>
<span class="hljs-section">&lt;/VirtualHost&gt;</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 &amp;&amp; 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>

View File

@@ -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="/">&lt;&lt; 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>

View File

@@ -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="/">&lt;&lt; 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
View 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;
}

View File

@@ -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>

View File

@@ -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="/">&lt;&lt; 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>

View File

@@ -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="/">&lt;&lt; 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>

View File

@@ -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="/">&lt;&lt; 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
View 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"
);

View File

@@ -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="/">&lt;&lt; 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>

View File

@@ -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="/">&lt;&lt; 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>