MacBook, defective by design banner

title:
Put the knife down and take a green herb, dude.


descrip:

One feller's views on the state of everyday computer science & its application (and now, OTHER STUFF) who isn't rich enough to shell out for www.myfreakinfirst-andlast-name.com

Using 89% of the same design the blog had in 2001.

FOR ENTERTAINMENT PURPOSES ONLY!!!
Back-up your data and, when you bike, always wear white.
x

MarkUpDown is the best Markdown editor for professionals on Windows 10.

It includes two-pane live preview, in-app uploads to imgur for image hosting, and MultiMarkdown table support.

Features you won't find anywhere else include...

You've wasted more than $15 of your time looking for a great Markdown editor.

Stop looking. MarkUpDown is the app you're looking for.

Learn more or head over to the 'Store now!

Wednesday, April 11, 2018

NOTE: I haven't reread/edited this one yet, I'm afraid. Bbl.


In Part 1, we had all the tools we absolutely required to make a single page app (SPA) with VueJS, but the HTML was a mess. Worse, if it got any more complicated and the different "views" shared any UI, we could tell it'd quickly stop being DRY.

The solution to this problem is to employ reusable components. Here's a quick visual from the "Intro to VueJS" video from Vue's home page.

VueJS Components "Slide"

Concentrate mostly on the stuff in the middle... we might want to use that Product Image component in a few different places, for instance. With components, we can define it once, and then reuse all over the place.

Now there are a number of different ways to create components, but, honestly, only a few that really make sense in a practical work environment. The first that we're going to review -- and the one most sites, including Vue's own documentaions start with -- really doesn't make great sense: inline text. But let's do it anyway for kicks. The reason will make more sense later...

Let's take that "cats" markup from Part 1 and componentize it.

Old markup:

<!-- ==== FROM HERE ==== -->
<div v-if="activeUi === 'cats'">
    <h3>Cats</h3>
    <ul>
        <li v-for="cat in cats">
            {{ cat }}
        </li>
    </ul>
</div>
<!-- ===== TO HERE ===== -->

<div v-else-if="activeUi === 'dogs'">
    <h3>Dogs</h3>
    <ol>
        <li v-for="dog in dogs">
            {{ dog }}
        </li>
    </ol>
</div>

<div v-else>
    <h3>Neither dogs nor cats</h3>
    <ul>
        <li v-for="x in others">
            {{x.name}}, a {{x.type}}

            <!-- And note that we can embed ad infinitum, natch -->
            <ul v-if="x.type === 'rooster'">
                <li>"That's a joke, I say, that's a joke son!"</li>
            </ul>
        </li>
    </ul>
</div>

Vue's component model is pretty conventional, and awfully familiar if you've used React. Here, there's no real business logic. We just need to get that the cats data into the component and then loop over it. And we do that with props, which is just a fancy way of saying properties that we bind in the component's declaration in our HTML.

Here the above cats-specific markup as a component. I've got it in a new file marked components.js so that it's not mixing with my core business logic, but you can drop it anywhere you want, as long as it's executed before your main Vue app instantiation. Recall that I've got my main Vue call in a document.addEventListener("DOMContentLoaded", function() {...}); wrapper, so it's not going until the rest of the page is read and rendered.

/*global Vue, window */
(function () {
    "use strict";

    Vue.component("cats", {
        props: ['store'],
        template: '<div><h3>Cats</h3><ul><li v-for="cat in store">{{ cat }}</li></ul></div>'
    });
}());

And here's how the HTML changes:

NOTE: Check the : before store, which tells us to bind the object represented by "cats" rather than treating it as a literal string.

<!-- ==== FROM HERE ==== -->
<cats v-if="activeUi === 'cats'" :store="cats"></cats>
<!-- ===== TO HERE ===== -->

<div v-else-if="activeUi === 'dogs'">
    <h3>Dogs</h3>

    <!-- ... and so forth... ->

That's certainly a lot cleaner, right? If we componentize it all, making similar dogs and others components, we exchange all the markup from the first code dump, above, to this:

<cats v-if="activeUi === 'cats'" :store="cats"></cats>
<dogs v-else-if="activeUi === 'dogs'" :store="dogs"></dogs>
<others v-else :store="others"></others>

A few things to note:

  1. Our HTML looks great. No clutter. If we want to see what happens with cats, we know to look at that specific component.
  2. The template string can include Vue markup. You see {{ cat }} there. So that's cool -- we can get as nesty as we want.
  3. The template string is okayish for the small markup we have, but boy, that'd be messy for lots of markup. It's not even easy to read as it stands!

I bet we can do better, right? Let's see if there's a way to keep the HTML in its own file, where we're not worried about newlines or surrounding values in single quotes, and escaping single quotes in the template, and...


Pros and Cons for VueJS Template Types

There's a decent intro to the different ways you can create templates for components in Vue here on medium from Anthony Gore. Let's run through them and list some pros and cons.

  1. String
  2. Template literal
  3. X-Templates
  4. Inline
  5. Render functions
  6. JSX
  7. Single page components

1. String

The first is what we just did. template is literally a string. As Gore says, "I think we can all agree that templates in a string are quite incomprehensible. This method doesn’t have much going for it other than the wide browser support." It's really not scalable, and heaven help anyone debugging or editing a large HTML value within quotes.

2. Template Literals

The second is to use es6's "template literals". This is a new syntax which allows us to define multiline strings using backticks instead of quotes to delimit strings. That's great, and would improve our cats component definition quite a bit...

Vue.component("cats", {
    props: ['store'],
    template: `
<div>
    <h3>Cats</h3>
    <ul>
        <li v-for="cat in store">{{ cat }}</li>
    </ul>
</div>`});

That's a big step up, but it's not IE happy at all. For me, at least, that's still an issue. There's also spotty escape sequence support, so it's not really HTML ready. And strangely, they don't have any compatibility right now (20180411) for Safari on iOS. ??

3. X-Templates (script tags)

X-Templates are when you use the trick that you can drop HTML into a script tag with an id and then link to it from your component definition. This allows you to embed all your components' html into a single file if you wanted, which is an improvement.

<script type="text/x-template" id="dogs-template">
    <div>
        <h3>Dogs</h3>
        <ol>
            <li v-for="dog in store">
                {{ dog }}
            </li>
        </ol>
    </div>
</script>

That, of course, can go anywhere you want in your html, or in a script include. This isn't an end of the world, and is actually how we used to do templates in KnockoutJS. The only thing I hate is that it feels a little kludge and that it's harder to get your editor set up to highlight the HTML code as HTML inside of script tags.

The component is very clean, however.

Vue.component("dogs", {
    props: ['store'],
    template: "#dogs-template"
});

4. Inline templates :^P<######

Inline templates are a horrible idea, and I can't even find a place on Vue's website that claims it's supported. I'm not saying it's not supported. I'm saying it's a horrible idea. Inline templating is when you put the template between the component's tags in your "parent" markup. Here's Gore's example:

<my-checkbox inline-template>
  <div class="checkbox-wrapper" @click="check">
    <div :class="{ checkbox: true, checked: checked }"></div>
    <div class="title"></div>
  </div>
</my-checkbox>

OMGWTFBBQ! The whole purpose of components is that you can then reuse them with minimal overhead. Now I get it -- perhaps there are times when you want different markup for each use of the component. Maybe. But if something's ever duplicated, you're stuck cut and pasting markup, and you've lost your DRYness. Yuck.

5. Render Function: Spoilers

I'm going to come back to render functions. *wink wink wink*

6. JSX & 7. Single file components.

The final two involve transpilation. You can use JSX in Vue if you want, just like you're back in React-land. Insert Kerriganian "WHY?!!?!"

The second is actually what you probably came to Vue for in the first place, single file components. I really do like the idea of single file components. They contain the template, javascript, and, get this, scoped CSS all in the same file. It sounds wonderful.

Here's why it's not, from vuejs.org:

For Users New to Module Build Systems in JavaScript

With .vue components, we’re entering the realm of advanced JavaScript applications. That means learning to use a few additional tools if you haven’t already:

  • Node Package Manager (NPM): Read the Getting Started guide through section 10: Uninstalling global packages.

  • Modern JavaScript with ES2015/16: Read through Babel’s Learn ES2015 guide. You don’t have to memorize every feature right now, but keep this page as a reference you can come back to.

After you’ve taken a day to dive into these resources, we recommend checking out the webpack template. Follow the instructions and you should have a Vue project with .vuecomponents, ES2015, and hot-reloading in no time!

To learn more about Webpack itself, check out their official docs and Webpack Academy. In Webpack, each file can be transformed by a “loader” before being included in the bundle, and Vue offers the vue-loader plugin to translate single-file (.vue) components.

NOTE: Either of these involve the gateway drug to that horrible cesspool of build scripts and maintenance that I'm trying to avoid for you. It's also a, well, JavaScript builds are not exactly a broken window; they're more like a stained glass window. Once you have a single piece of stained glass, someone on the team is going to add eighteen more build steps^H^H^H^H^H^H pieces of stained glass, and suddenly you have a priceless stained glass window that looks like a snowflake, if you get my [wait for it...] drift. Rimshot

Again, this is how everyone does JavaScript development these days, but I'd warn you against it. At the very least, let's see how bad things get if we avoid transpiliation, if just as a thought experiment. The series is called "Templating without Transpilation", after all.

Tune in next time in Part 3, when we finally get where we're going, using, you guessed, it, render functions, and have a solid architecture that allows templating without transpilation.

Labels: , , ,


posted by ruffin at 4/11/2018 12:37:00 PM
0 comments
Sunday, April 08, 2018

I heard about VueJS a while back on from Shawn Wildermuth guesting on Yet Another Podcast, and figured I'd take a look. The most interesting thing about it was its claim to be a "progressive framework"...

From vuejs.org:

Vue (pronounced /vjuː/, like view) is a progressive framework for building user interfaces. Unlike other monolithic frameworks, Vue is designed from the ground up to be incrementally adoptable. The core library is focused on the view layer only, and is easy to pick up and integrate with other libraries or existing projects. On the other hand, Vue is also perfectly capable of powering sophisticated Single-Page Applications when used in combination with modern tooling and supporting libraries.

Incremental adoption, you say? As in, I could use its templating without any other libraries? RLY? I mean, Vue bills itself to be a pretty mature lib. Heck, you can go full-bore, Babel and JSX with VueJS if you want to. That marks a sort of max progression. Can we find a similarly minimally progressive stack?

Once burned...

Last year, I spent most of my time working on a system that used React, JSX, and MobX using Babel for transpilation. It wasn't a horrible client-side stack, but I've never wasted so much time on build systems since I was new to ant. We updated and debugged with each new release of anything of those three, and it drove me crazy with what Shawn Wildermuth calls the "ceremony" of coding -- all the magic incantations and rituals you have to go through and maintain before working code comes out.

Using transpilation and riding the bleeding edge instead of writing deployable code means everything you do costs you -- let's say -- an extra 10%, and, in the wrong hands, more. Do you really get that time back with transpilation?

Just because everyone else is putting together complex JavaScript build processes (and they are. Projects that don't include "the dev who maintains the build" are becoming few and far between, and that dev is always front and center on interview calls pretending their role is absolutely critical to a project's success), do we have to go full Cranberries? (pro tip: see album title, young'uns)

I don't think so. I'm not against transpilation, if it's well managed. But if I can use a library that doesn't require transpilation, but can still give me a good templating system, I'm curious. Just for fun, let's see if VueJS can keep us transpilation-free.

How progressive is VueJS, exactly?

NOTE: If you already know Vue, stay with me. Skim the balance of this so you know where I'm coming from, and then stop at the end, where I start talking about what's missing. Then tune in next time, for Part 2, where I fill in what's missing & seal the deal.

Let's take the minimal VueJS setup as described in their introductory guide, where we assume zero libraries other than Vue are present.

What's below is the minimal Vue setup from their guide, with just enough changed so that we...

  1. Have something that'll work in a live example
  2. Include a form element to test our binding
  3. Have a button to access our data programmatically (standing in for a call back to the server)
  4. Wait until the DOM has loaded before initializing to begin templating
    • If we were using true Vue templates, we wouldn't have to do this. More on that in Part 2.
  5. Some gymnastics to pass JSLint.

Excuse the last. It's an unshakeable addiction.

(That said, you should use JSLint too. ;^D)

/*global Vue, window */
document.addEventListener("DOMContentLoaded", function() {
    "use strict";
    window.app = new Vue({
        el: '#app',
        data: {
            message: 'Hello Vue!'
        },
        methods: {
            report: function () {
                // Note that it's app.property, not app.data.property
                console.log(JSON.stringify(window.app.message, null, "    "));
            }
        }
    });
});

And the HTML needed to match is super simple.

<html>
    <head>
        <title>Look how simple</title>

        <script src="../vue.js"></script>
        <script src="./app.js"></script>
    </head>
    <body>
        <div id="app">
            {{ message }}<br />

            <input
                type="text"
                v-model="message"
            /><br />

            <button
                type="button"
                v-on:click.prevent="report"
            >Add new</button>
        </div>
    </body>
</html>

And poof! We've got an interactive, VueJS-templated web page.

What an insanely basic VueJS web page looks like

That's... great. Right?

Vue does observables right

Actually, it is great, kinda. data is just a datastore. Vue wraps it in observable overhead, so in many ways, it reminds me, at this level, of KnockoutJS. It's advantage? That we're not wasting time dealing with any of that overhead ourselves, in code or our mental model. Knockout had this horrible convention where you had to call a function to get a "raw" observable, which often threw people for loops).

Vue beats out KnockoutJS easily here. You can very simply put in properties to serve as hooks in your data object to hang all of your datastores, and when you set them, they iterate through your object models and make everything an observable too. If you set message, above, to some giant json model, all of that model would be observable. And each property would be accessible in plain old javascript object ("POJsO") notation.

/*global Vue, window */
document.addEventListener("DOMContentLoaded", function() {
    "use strict";
    window.app = new Vue({
        el: '#app',
        data: {
            payload: {
                b: { c: 2 }
            }
        },
        methods: {
            report: function () {
                // Note that it's app.property, not app.data.property
                console.log(JSON.stringify(payload.b.c, null, "    "));
            }
        }
    });

    // Pretend some event caused this.
    window.app.payload = {
        a: 1,
        b: {
            a:"a",
            b:"b",
            c:"c"
        },
        c: 2
    };
});

And then a quick change to our html...

<div id="app">
    {{ payload.b.c }}
</div>

That, I like. That's how you should do observables. It's the same mental model as a plain ole JavaScript object. There's no "oops, that's an observable! Remember to treat it like a function!" overhead. It's simply magic.

Okay, okay, I haven't looked, but it's almost certainly some getter and setter overhead, which works like magic here. That's why it's important to note that window.app.data is inaccessible. What we don't want to do is blow up our observable chain.

How not to observe...

NOTE: The follow-on from that is that you can't do this:

window.app.payload.d = "spam" and expect spam to be observable. You have to set something that's already an observable, or the extra setter logic won't fire. That just makes sense.

d is not an observable

But you can pick up the observable train wherever you want...

insert alt text

NOTE: You really shouldn't be updating your data object's object model for the most part, however. That's a code smell, imo. You'll be getting nice large JSON payloads from your server, and you might have some navigation and convenience objects for managing views, but that's about it. If you make changes to data, that should be going back to the server. And if you're changing the data model on the client, that's probably a business rule that should've been handled on your server-side, not the client-side, where your interest should be almost exclusively presenting views.

Keep your interests separated.

Cool side cool

Moving towards an SPA

There are really only two more things you need to know to get pretty close to making minimalistic single page apps (SPAs) with VueJS: conditionals and loops.

Loops with v-for

Loops are easy. If you have an array of objects in your datastore, you can loop through them easily with v-for, repeating the markup within that marked node as many times as you have objects.

So if you had data = { stooges: ["Larry", "Moe", "Curly", "Shemp"] }, your markup would be something similar to:

<div id="app">
    <ul>
        <li v-for="stooge in stooges">
            {{ stooge }}
        </li>
    </ul>
</div>

Easy. And if your stooges were objects instead of strings, that's done just like you'd expect, thanks to the POJsO setup Vue supports.

data = { 
    stooges: [
        { name: "Larry", desc: "the curly-headed one." },
        { name: "Moe",   desc: "the relatively smart one." },
        { name: "Curly", desc: "the bald one. See what they did there, with Larry having the curly hair?" },
        { name: "Shemp", desc: "the one nobody knew in the 70s, but somehow everyone did starting around 1990." }
    ]
};

And change the markup to match:

<div id="app">
    <ul>
        <li v-for="stooge in stooges">
            {{ stooge.name }} is {{ stooge.desc }}
        </li>
    </ul>
</div>

Conditionals with v-if

Now let's look at conditionals. If you only want something to be rendered when some condition is true, you plant that portion of your markup in a conditional.

 <html>
    <head>
        <title>Animal types and examples</title>

        <script src="../vue.js"></script>
        <script src="./app.js"></script>
    </head>
    <body>
        <div id="app">

            Display all animals of type: <input
                type="text"
                v-model="activeUi"
            /><br />

            <div v-if="activeUi === 'cats'">
                <h3>Cats</h3>
                <ul>
                    <li v-for="cat in cats">
                        {{ cat }}
                    </li>
                </ul>
            </div>

            <div v-else-if="activeUi === 'dogs'">
                <h3>Dogs</h3>
                <ol>
                    <li v-for="dog in dogs">
                        {{ dog }}
                    </li>
                </ol>
            </div>

            <div v-else>
                <h3>Neither dogs nor cats</h3>
                <ul>
                    <li v-for="x in others">
                        {{x.name}}, a {{x.type}}

                        <!-- And note that we can embed ad infinitum, natch -->
                        <ul v-if="x.type === 'rooster'">
                            <li>"That's a joke, I say, that's a joke son!"</li>
                        </ul>
                    </li>
                </ul>
            </div>

        </div>
    </body>
</html>

All three states displayed from the animal types and examples example

You're half-way there. To an SPA, that is.

If you use conditionals with reckless aplomb, you could force your way to a complete SPA. No, really, you're done. You could have every portion of your app in some div marked with the proper conditional, and have everything appear iff it's supposed to.

There're just two problems. At some point, it's going to be very difficult to keep this DRY. You will eventually want to use the same markup (HTML) and business logic (JavaScript) in two places that are each embedded deep within some other portion of HTML.

And, well, that's HTML is already a mess. It's sprawling and difficult to grok quickly, which means it'll be difficult to maintain.

Wouldn't it be nice if we could cut that previous html down with some custom components, like this?

 <html>
    <head>
        <title>Animal types and examples</title>

        <script src="../vue.js"></script>
        <script src="../components.js"></script>
        <script src="./app.js"></script>
    </head>
    <body>
        <div id="app">

            Display all animals of type: <input
                type="text"
                v-model="activeUi"
            /><br />

            <cats store="cats" v-if="activeUi === 'cats'" />
            <dogs store="dogs" v-else-if="activeUi === 'dogs'" />
            <other store="others" v-else />

        </div>
    </body>
</html>

... and to do it without transpilation?

We can. And we will. In Part 2.

Labels: , , ,


posted by ruffin at 4/08/2018 09:10:00 PM
0 comments
Thursday, April 05, 2018

About a week and a half ago, I compared the CPU Mark scores for three inexpensive programmers' laptops. Just for my own benefit, and so I stop looking it up over and over myself, here's what the current "entry level" MacBooks give you:

2017 entry level MacBook benchmarks

So compared to my cheap-o Windows laptops, not great, though the "Escape" is probably workable. Here, again, are the Acer Aspire with i3, i5, and what I have now (the i7-7700HQ).

Old scores of Acer Aspires and my Y700

I was wondering if I'd bite on a Mac Pro if one dropped in time for WWDC, since I've been considering a prebuilt tower, but now that we know there's no Mac Pro until 2019, that's not an option either.

It kinda stinks. I've got an excuse to upgrade -- my Windows laptop's battery's age and dated Mac laptop -- but nothing good enough to let me turn that excuse into a true reason to buy. Wish there was a MacBook that was "close enough" to justify the Mac tax.

Which leaves me back at the completely uninspiring but insanely practical & affordable Aspire 15 I mentioned last time or wait and see if we can't get a summer speed bump for the Escape.

Labels: , , ,


posted by ruffin at 4/05/2018 06:30:00 PM
0 comments
Tuesday, April 03, 2018

From recode.net:

The big labels provide Spotify with the music that makes up 87 percent of the company’s streams. Spotify provides the labels with billions in revenue, which is starting to replace the vanishing money the labels used to make from CD sales and digital downloads.*

But Spotify’s plans for the future do involve changing that relationship in the long run.

The idea, according to people familiar with the company’s plans, isn’t to cut out the big music labels, or compete directly with them by signing acts to recording deals.

Spotify does imagine, however, that over time, a growing tier of music acts, or small independent labels, won’t use the big labels for distribution. Instead they’ll work directly with the streaming service.

(Let's take a second to note that that last sentence really does say, "Compete directly with them by signing acts to recording streaming deals." Though obviously what they're trying to avoid is what recode mentions further down... "If Spotify goes after our big acts, we’ll go nuclear. Good luck running a streaming service without our songs — not just the new ones, but our old catalog, which accounts for the majority of our streams." And there's the anachronism that explains why we have striated music services today.)

I'm waaaay late to the bandcamp party, but I finally mainlined it a bit a few weeks ago. It's not knock-down, drag-out great music, but there's a lot to discover in there. The search interface is exceptionally limiting, for some reason, not allowing complete freedom to pick from what's a pretty nice set of music types, but once you invest some time, you'll pull out a few good bands, seemingly whatever your preference.

And if Spotify could be the music recommendation service I wish Apple Music was, it'd be on to something.

You got chocolate on my peanut butter

This really is a Reese's Cup commercial. All the parts are out there, and working well. More important than bandcamp is what it represents: indie music has the tools to release high-quality music to the web with hundreds of dollars worth of gear. No longer do they need radio and labels. And there are services that do a good job with music discovery.

Somebody just needs to get that last barrier to entry -- having "all the musics" on the same competent discovery service -- out of the way so that they can move on to Step 3. Profit.

Labels: , , , , ,


posted by ruffin at 4/03/2018 08:51:00 AM
0 comments
Friday, March 30, 2018

Here's an interesting post on the SourceTree development blog about why they believe their changes to the UI in the last few years are better, and here's another than explains changes to the Windows client specifically.

I get the sentiment of some of the changes, like this one...

The Windows App always used tabs for navigating between open repositories, but we knew that those tabs weren’t quite right. The toolbar sat above everything else in the UI, but it only really belonged to the open repo (tab). We’ve swapped those panels so that tabs now live at the top of the hierarchy, much like browser experiences that you are no doubt familiar with.

... but I don't necessarily get the conclusions. You want to have a coherent design philosophy, like Material Design or Apple's User Interface Guidelines, sure. But I've never noticed tab placement to be a problem in SourceTree. I get that it's not a browser look, but also wonder why we need to standardize on browser behavior. Is overuse of tabs in Windows apps a convention in itself? Probably was. Do newer Windows users balk at that convention and prefer browser conventions? Maybe. I don't know. I didn't see a lot of A/B testing in the SourceTree articles.

What I do know is that I hate the flatness of the newer SourceTree. I also hate how spaced out each line for a checkin is. It's disorienting and not as info rich as the alternating colors version we had previously. I also dislike the icons in the toolbar. Before, the icons were colorful, but not distracting. Now they're as flat and non-descript as a Jony Ives' designed button on iOS 7.

I posted a discussion on their forums, not that I expect to see much in the way of responses.

Just for fun, I thought I'd ask if anyone else preferred the UI from back in 1.7. To my eyes, at least, it's much less fatiguing to take in at a glance than the flatness of more recent releases, with nice, though old-school, cues about where widgets start & stop. Sort of like having serifs in a font.

The colors are also more muted, giving information rather than everything demanding attention at once in an overly egalitarian fleet of brightness floating on a flat sea of white.

(I do kinda like that last line in the quote, above.)

But one of the neat things about their own blog posts is that they do seem to care what you think. In that first that I linked to, you could schedule a 1:1 with them to discuss what you thought about design. Let's just go ahead and say that's crazy customer attention. ;^) And they ask for community posts if you have an opinion, so I'm doing my part, I guess.

Makes you wonder, though.

  • How much attention and how much of a company's resources are put into UI where it's not useful?
  • How can you tell?
  • Do you embed metrics in your apps once they're released to measure real-world use?
  • Is real-world A/B testing enough?

I mean, Linux still hasn't taken over the desktop for vanilla PC users. Why is that? Just apps? I'm betting there's some UI roughness that's also a barrier to entry. Good enough [for functional use] isn't always good enough [to sell (or be eaten?) like hotcakes]. And it's specifically these kinds of changes... less information, buttons being moved to different spots... that are the microactions that make everyone's day to day that much less productive.

Labels: , ,


posted by ruffin at 3/30/2018 12:32:00 PM
0 comments
Wednesday, March 28, 2018

From martinfowler.com on "Command Query Responsibility Segregation", or CQRS:

The mainstream approach people use for interacting with an information system is to treat it as a CRUD datastore. By this I mean that we have mental model of some record structure where we can create new records, read records, update existing records, and delete records when we're done with them. In the simplest case, our interactions are all about storing and retrieving these records.

As our needs become more sophisticated we steadily move away from that model. We may want to look at the information in a different way to the record store, perhaps collapsing multiple records into one, or forming virtual records by combining information for different places. On the update side we may find validation rules that only allow certain combinations of data to be stored, or may even infer data to be stored that's different from that we provide.

CQRS image

As this occurs we begin to see multiple representations of information. When users interact with the information they use various presentations of this information, each of which is a different representation...

This structure of multiple layers of representation can get quite complicated, but when people do this they still resolve it down to a single conceptual representation which acts as a conceptual integration point between all the presentations.

The change that CQRS introduces is to split that conceptual model into separate models for update and display, which it refers to as Command and Query respectively following the vocabulary of CommandQuerySeparation. The rationale is that for many problems, particularly in more complicated domains, having the same conceptual model for commands and queries leads to a more complex model that does neither well.

I saw this acronym for the first time today in a SO question about Azure Service Fabric, and my HOT TAKE!!11! was, "Who in the world doesn't do this?"

There are two main data transformations that happen in essentially all of my controller code. For GETs, I'm usually flattening a "database is truth" model into a data payload, stripped of stuff like, "LastModifiedBy" (or anything not needed by the client), but also of complex relationships with child objects. That is, when Entity Framework (or any POCO-returning library) gives me, say, an address' stateOrProvince as an entity, I usually flatten that to a StateName and StateId at the top level of a client-ready DTO for Addresses (or at the Address level on a collection of Addresses attached to a client).

The second is when I return changes to these DTOs. There, the PUT (or PATCH) command often isn't strictly RESTful either [using the database as The Source of Truth]. If I'm returning the ever-proverbial Contact with three Addresses, I don't typically call an Addresses endpoint with a PUT thrice, and then follow up with another PUT to Contacts. I'll send up a DTO that's essentially CompositeContactWithAddressesAndOtherJive (but with a better name, like ContactDTO). And though if I'm trying to keep our stack small in cases where team familiarity with SQL isn't a strong suit, I will, occasionally, still hit EF repository collections, I usually prefer to write the INSERT/UPDATE SQL by hand and perform what needs doing in as few optimized calls as possible. The move away from the ORM for PUTs hurts if you ever want to swap out your database engine, of course, but who swaps out their database engine? Talk about premature optimizations. Why should nearly every PUT suffer when you're likely hiring for SQL proficiency? For a clean object model? Stop it. Use your team's skills.

There is nothing that, in my experience, causes performance bottlenecks as quickly as folks blindly falling back on performing Commands (actions that "Change the state of a system but do not return a value") via fully hydrated ORM objects. Oh, the humanity.

Treating your PUTs and PATCHes as separate models from your GETs (or at least separate models from those in your database schema) allows you to spare yourself such madness.

Labels: , , ,


posted by ruffin at 3/28/2018 01:51:00 PM
0 comments
Sunday, March 25, 2018

The battery in my Lenovo Y700-14ISK is finally getting to the point that it's holding me back. I might get 60-70 minutes out of it just with casual programming. That's not crazy. It's a gaming laptop, and it's obviously meant to stay plugged in. It also has a pretty phat processor for a laptop (an i7-7700HQ) that made it an attractive programmer's box two years ago.

But two years later, the battery's ready to go.

I've been waiting for a MacBook that was worth buying, and that I dodged buying two years ago with this Lenovo, and I remain hopeful yet again that this will be the year to get back to portable macOSing.

I want portable Windows with battery life, but I don't want to break the bank to buy a ThinkPad, since I'm planning to grab a Mac this buying cycle as my "real" work box.

I've purchased stuff like the cheap IdeaPads before, and they're more computer than you've paid for. Great battery, decent keyboard, and almost able to keep up with server and javascript work. But, ultimately, not fast enough for real production.

Acer Inspire: Where has this been?

Then I ran into the Acer Inspire while looking at cheapy laptop comparisons on Amazon. Wow. Look at these two...

  • Acer Aspire E 15 E5-575-33BM for $350!
    • 15.6-Inch
    • Intel Core i3-7100U 7th Generation
    • 4GB DDR4
    • 1TB 5400RPM HD
    • Intel HD Graphics 620
    • Windows 10 Home
    • Looks like a real 9-10 hours of battery !?!!

That's not bad, but the real kicker is that it seems like this laptop was made for people willing to upgrade. Look inside this thing:

access panel on Acer Inspire 15

One panel and you've got your SATA drive, RAM, and an m.2 slot accessible. It's like they expected you to swap and/or upgrade this box! Insane!

But once you start adding up RAM and an SSD, well, you're pushing up to around $550. Which almost exactly where the Inspire's next step up lives:

  • Acer Aspire E 15 E5-576G-5762 for $600
    • 15.6" Full HD,
    • 8th Gen Intel Core i5-8250U
    • GeForce MX150
    • 8GB RAM Memory
    • 256GB SSD
    • Same 9-10 hours of battery life.

Well, hello. This is getting close to too much to pay for making Windows portable, but isn't the better processor worth an extra $100? Here are some ballparks from cpubenchmark.net -- this first is the i3 in the cheap Inspire, then the i5 in the $600 version, then the one I got in my Lenovo:

i3-7100U vs i5-8250U vs i7-7700HQ

Now, for $250 over the cheap Inspire, we get an SSD (though not the one I'd've purchased, and we lose the TB of spinning platter space) and just enough RAM to squeeze by for a while -- and the chance to upgrade to 32! That's nice. Eat 32 gigs, MacBook Pro.

And the processor? Those numbers are close enough to my old i7, I could probably trade it in and not feel it too badly.

It's bigger than I'd like. I don't need the DVD drive. It's still got VGA, which even I finally removed from my desk setup recently. The Inspire is a dinosaur.

But it's an easily upgradeable dinosaur with a good drive & the latest processor for $600. That, my friends, is a proverbially impressive piece of kit.

Do I worry about the cheap keyboard? Yes. Yes and no.

ThinkPad keyboard overlain on laptop

Six hundred simoleons is a bit more than I wanted to spend for the equivalent of a new battery. I always think, "If you could have $X off of your next laptop by not buying now, what could you the afford to get?" And $600 would be nice to put towards a MacBook Pro with its own nice battery.

But any way you slice it, if you want a nice Windows box for some work, and don't mind not having Pro, the Acer Inspire looks like it should be your value baseline.

Labels: , , , , ,


posted by ruffin at 3/25/2018 12:17:00 PM
3 comments

Support freedom
All posts can be accessed here:


Just the last year o' posts:

URLs I want to remember:
* Atari 2600 programming on your Mac
* joel on software (tip pt)
* Professional links: resume, github, paltry StackOverflow * Regular Expression Introduction (copy)
* The hex editor whose name I forget
* JSONLint to pretty-ify JSON
* Using CommonDialog in VB 6 * Free zip utils
* git repo mapped drive setup * Regex Tester
* Read the bits about the zone * Find column in sql server db by name
* Giant ASCII Textifier in Stick Figures (in Ivrit) * Quick intro to Javascript
* Don't [over-]sweat "micro-optimization" * Parsing str's in VB6
* .ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture); (src) * Break on a Lenovo T430: Fn+Alt+B
email if ya gotta, RSS if ya wanna RSS, (◔_◔), ¢, & Δ if you're keypadless


Powered by Blogger etree.org Curmudgeon Gamer badge
The postings on this site are [usually] my own and do not necessarily reflect the views of any employer, past or present, or other entity.