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.

As an Amazon Associate, I earn from qualifying purchases. Affiliate links in green.

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!

Tuesday, June 15, 2021

Okay, one thing I hate in JavaScript code is all the code around AJAX requests.

jQuery has a wrapper. And AngularJS has a wrapper. And RxJS has a wrapper. And...

Why don't we just use XMLHttpRequest? Then our services, which are often fairly UI-templating-agnostic already, can live anywhere we want.

There are at least two good reasons... The first is to handle JSONP. I'm ignoring that for now.

The second is to handle async code in a manner that's conventional for each templating engine. $http in AngularJS, for instance, uses $q in place of Promises to ensure changes are communicated correctly to AngularJS. RxJS returns things as Observables (RxJS specific, give or take) rather than Promises (which is a standard), though this is easy to work around.

It's probably worth saying that, well, first that I stole the framework for this code from a SO answer, and second that this is a great example of how to hand-roll a Promise. Just call resolve or reject when you're ready and poof, you've got a Promise.

For the most part, however, you can pass the data event back into the templating system's change detection scheme fairly easily.

So I wanted to write a quick XMLHttpRequest library one could use for the vast majority of CRUD operations. I've only got CR below (give or take. Let's not get into POST vs PUT for the time being), but you get the picture.

I'll try to edit this as I make changes. Comments welcome.

The bottom line, though, is that this is not difficult code. Why we thought we needed wrappers to make AJAX calls I'll never know. The longer you can resist context-specific code, like library-specific wrappers, the longer your original code can live.

(See Exhibit VanillaJS (or the more useful, but strangely mascoted, competing Vanilla JS project).)

Yes, this is, in contrast to my original goals, in TypeScript. It's a pretty easy port. But seriously, you should be using TypeScript.

export default class BaseService {
    getOneUntyped(url: string, id?: string): Promise<any> {
        return new Promise((resolve, reject) => {
            let request = new XMLHttpRequest();

            request.onerror = function () {
                reject(`No response was given.`);
            };

            request.onreadystatechange = function () {
                console.log(request.readyState, request.status);

                // 4 === DONE
                if (request.readyState === 4) {
                    // 200 === OK.
                    if (request.status === 200) {
                        resolve(JSON.parse(request.response));
                    } else {
                        // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/status
                        // Before the request completes, the value of status is 0.
                        // Browsers also report a status of 0 in case of XMLHttpRequest errors.
                        if (request.status !== 0) {
                            reject(`${request.response} ${request.statusText}`);
                        }
                    }
                }
            };

            let urlToUse = url + (id ? id : "");
            request.open("GET", urlToUse, true);
            request.send();
        });
    }

    postOneTyped<T>(url: string, payload: T): Promise<boolean> {
        return new Promise((resolve, reject) => {
            var request = new XMLHttpRequest(); // new HttpRequest instance
            request.open("POST", url);
            request.setRequestHeader("Content-Type", "application/json");
            request.send(JSON.stringify(payload));

            request.onerror = function () {
                reject(`No response was given.`);
            };

            request.onreadystatechange = function () {
                console.log(request.readyState, request.status);

                // 4 === DONE
                if (request.readyState === 4) {
                    // 201 === Created.
                    if (request.status === 201) {
                        resolve(true);
                    } else {
                        // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/status
                        // Before the request completes, the value of status is 0.
                        // Browsers also report a status of 0 in case of XMLHttpRequest errors.
                        if (request.status !== 0) {
                            reject(`${request.response} ${request.statusText}`);
                        }
                    }
                }
            };
        });
    }
}

Labels: , , ,


posted by ruffin at 6/15/2021 10:30:00 AM
Monday, February 20, 2017

From Jslint Is Not A Code Quality Tool For 3rd Party Code โ€“ Hugh FD Jackson:

Crockford is an opinionated, experienced and charismatic guy. As such people often do, he has gained significant influence. In this post, Iโ€™m going to focus on what Crockford thinks the role of JSLint is, as typified by this suggestion:

โ€œThere is one reliable, objective metric of JavaScript code quality that can help you in making your choice [โ€ฆ of library โ€ฆ]: JSLint. If JSLint finds problems in a library, then dump it and move on to the next one.โ€

I firmly believe that this attitude is damaging; and worth focusing on given his potential influence.

Yeah, wow, no. That is bad advice.

As I've said on Stack Overflow before:

As a rule, you should exempt 3rd party libraries from your linting. There's nothing you can do about external libraries unless you want to fork them and lint them yourself, which is, well, insane. ;^) And, again, minified code often takes shortcuts that aren't lint-friendly.

Lint your code before you minify to keep its quality high, but don't worry about QAing libraries you shouldn't be touching anyhow. Assume they have another method for ensuring high quality, which might include using a different linter, or a linter with a different set of rules.

I'm a huge fan of linting your JavaScript code, and there's no more thorough linter for less investment on your part than JSLint. Nothing it forces you do is objectively wrong, and you don't have to worry about getting everyone in a room to set up an ESLint rule set before you get started.

But there's absolutely no reason not to use libraries that aren't themselves lintable in their original. There's a clear interface between you and that code. It's sort of like how RMS wishes you wouldn't use any non-GNU code. A proscription from using non-JSLinted libs is more political than rational.

Labels: , , , ,


posted by ruffin at 2/20/2017 08:42:00 AM
Tuesday, February 14, 2017

From Netscape Goes Bonkers โ€“ Joel on Software:

The sheer volume of bugs, it seems, proves that rewriting code from scratch does not make for a better code base, it makes it worse. Old code doesnโ€™t rust, it gets better, as bugs are fixed.

Someone should tell that to StackOverflow.

New (2017) StackOverflow menubar

Oh, I know, I know. This is design, you say, not code as such. But riddle me this, Batman: Was anyone not using SO because of the design?

I'm going to hazard a guess that the code behind that menubar/toolbar was heavily refactored too. Could be wrong. Hope I'm wrong. Idk. But in either event, I'm not sure the old site's design had rusted.

Labels: , , ,


posted by ruffin at 2/14/2017 09:07:00 AM
Tuesday, October 11, 2016

From Microsoft's How to: Verify that Strings Are in Valid Email Format Code Example for Microsoft's email validity check

Oh please, heavens, say it isn't so.

Sounds more like a Dune quote, doesn't it?


EDIT: Some decent advice:

Defence in depth only works if each level of your security onion is not rotten. One rotten layer means you spoil the whole onion. Rejecting "foo@example.com.au" because you want to defend against vulnerabilities in Sun's ยต-law encoding doesn't make sense, does it? Don't laugh, it's happened to me. The reason I am here commenting is that Medicare Australia doesn't allow ".au" addresses, only ".com". Also read Mark Swanson, "How not to validate email, ",ย mdswanson.com/blog/2013/10/14/โ€ฆย โ€“ย ManicDeeย Nov 22 '13 at 5:21

And then from the linked post, "How now to validate email":

Or maybe you will find a regular expression that looks something like ^[_a-z0-9-]+(\.[_a-z0-9-]omg-whyyyyy$. ... So what should you do instead? Just check for the existence of @. Every email address will have at least one of them and it is trivially easy to write this code.

As I mentioned on SO...

The buttoned up coder in me is trying to resist, but the rest is surprisingly convincingly arguing that anything else is a sad tragedy of micro-optimization.

Just fwiw, I'm also checking for a length of at least one before and after the last @, though I haven't looked at the format for comments inside of an email address [sic!!].

public static bool IsValidEmail(this string str)
{
    // See https://myfreakinname.blogspot.com/2016/10/spaghetti-code-leads-to-suffering.html#emailValidationEdit
    // for the reasoning behind this.

    int lastAtLoc = str.LastIndexOf('@');
    return lastAtLoc < str.Length - 1 && lastAtLoc > 0;
}

Labels: , , ,


posted by ruffin at 10/11/2016 02:40:00 PM
Saturday, January 17, 2015

I (he said uncontroversially) agree with Jon Skeet -- I'm not sure why converting to quoted printable isn't already in C# somewhere. It's old as the hills, and email seems it'll keep it going for the foreseeable future.

I've seen some wacky ways of trying to do this, but it's really pretty easy. There are only two rules. You take a collection of bytes, here an array, and in the first rule, you only have two options. Either it's a "normal" byte -- which is between 33 and 127, inclusive, but exclusive of 61 (decimal) (since that's the =) -- or it's not. If it is, you add its ASCII char equivalent to the string. If it isn't, you add = plus the string representation of the byte as a two-digit hexadecimal number.

The only monkey wrench is the second rule: that no line can be more than 76 characters, though apparently you can cut any line you want shorter than that. So if the line you're on is 75 characters long already & you're adding a "normal" or if it's 73 characters or greater and you're adding a "non-normal", you need to add a = to the end of the line to let a parser know it's not really a new line of text yet. Then you add (always) a carriage return and line feed. That is, in another [more complicated] manner of speaking, package your data with a \r\n between every 75 characters (treating =$$ as a unit) except, if you're encoding data that is text, you don't escape your new line bytes, and the counting starts from zero after a textual new line.

Simple, right? Either/or check for byte values with a line length check.

public static string ToQuotedPrintable(this string self)
{
    byte[] bytes = System.Text.Encoding.UTF8.GetBytes(self);
    StringBuilder sbInner = new StringBuilder();
    StringBuilder sbOuter = new StringBuilder();

    foreach (byte byt in bytes)
    {
        int charLenQP = (byt >= 33 && byt <= 126 && byt != 61) ? 1 : 3;
        if (sbInner.Length + charLenQP > 75)
        {
            sbOuter.Append(sbInner + "=\r\n");
            sbInner = new StringBuilder();
        }

        if (1 == charLenQP)
        {
            sbInner.Append((char)byt);
        }
        else
        {
            sbInner.Append("=" + byt.ToString("X2"));
        }
    }
    sbOuter.Append(sbInner);
    return sbOuter.ToString();
}

I think that's right.

QUICK NOTE: I am encoding in UTF-8 every time right now. You could take that in as a parameter (maybe with a UTF-8 default), but the best case would be to send in a byte array from the start, which would let you decide your own encoding, but then we couldn't use it as a fancy string extension. Though perhaps it should be a byte array extension, eh? That might make more sense.

Labels: , , ,


posted by ruffin at 1/17/2015 10:00:00 PM
Wednesday, September 26, 2012

Surprisingly little about this on the web, at least from where I'm sitting. I want to create reusable panels in ExtJS, and the inherited code for the project I'm coding doesn't quite understand how it's done. Instead of extending ExtJS components, like the Panel, it creates generic object types that wrap around the components instead. So you have to run myObj.myPanel to get to Panels rather than just myCustomPanel. Weird.

I have ExtJS in Action by Jesus "Jay" Garcia, which is pretty good, but his extension example skips past the simplest case for some reason and dives right in to a filled out example. And the extension example is a singleton. He doesn't really extend a type and instantiate several times until he's going 55 into plugin creation.

Anyhow, here's some code. Just a half baby step past the trivial implementation, so that we can play around a little.

PnlCustom = Ext.extend(Ext.Panel, 
{
        title: "Title",
        html: "spam",

        initComponent : function(){
                PnlCustom.superclass.initComponent.call(this);
                if (null == this.someVal)       {
                        this.someVal = "NOTHING";
                }
                console.log("#" + this.someVal + "#");
        }
});

Ext.onReady(function()  {

        var pnlCustom = new PnlCustom({
                someVal: "3"
        });
        var pnlCustom2 = new PnlCustom({});

        var pnlPlain = new Ext.Panel({
                title: "TITLE",
                items: [
                        pnlCustom,
                        pnlCustom2
                ],
                renderTo: "uiHook"
        });
        //Ext.Msg.alert("test","test"); // compulsory test that Ext is set up correctly.
});
The only other thing you might want to consider is if you want to throw extra "procedural" code into initComponent or the constructor function. There's plenty on the web to help you with that, including some stuff on StackOverflow with one comment that refers to text from one Jay Garcia's books. For now, initComponent is fine.

Also remember that I was looking for an ExtJS 2.2 simplest case. There is some decent (not great, afaict) stuff on 3+.

EDIT: Man, complicated. You can't use your typical Swing/Windows.Forms mental model when building ExtJS UI elements. The items collection can't be accessed inside of a definition of an extended object. Check out this thread (Jay's & Condor's answers are quite useful) to see how what you're apparently really doing is defining a prototype, not a class, per se.

Labels: , ,


posted by ruffin at 9/26/2012 11:55:00 AM
Monday, September 17, 2012

In prog:

window.onload = function() {
document.getElementsByTagName('body')[0].onkeyup = function(e) {
var ev = e || event;

if (ev.keyCode)
keycode=ev.keyCode;
else
keycode=ev.which;

console.log(keycode);

// http://tinyurl.com/y8jjah3
if (keycode==113 && (ev.charCode ? ev.charCode : 0) == 0) {
console.log("hello F2");
}
}
};

Labels: , ,


posted by ruffin at 9/17/2012 10:48:00 AM
Thursday, August 23, 2012

How do you do it? Here's the quick answer:

SELECT
CASE
WHEN TRIM(FIELD_MAYBE_NULL) is NULL THEN FIELD_NEVER_NULL
ELSE FIELD_NEVER_NULL || ', ' || FIELD_MAYBE_NULL
END AS CONCATTED_FIELD

FROM TABLE


Course it helps that NULL = '' in Oracle.

Labels: ,


posted by ruffin at 8/23/2012 04:29:00 PM
Wednesday, August 22, 2012

What a pain. I've wasted hours trying to take in an index and produce a unique color to go with it. Here, it's to create icons that represent which table, out of over six-thousand, is a particular attribute's origin. It's impossible to come up with 600, much less 6000, easily discernable colors, I think. But this seems to work as well as it's going to without displaying more than one color at a time.

<head>
<script>
function determineViewRGB_stepped(i) {
        var intNum = 10;
        var lumStart = 80;
        var lumStep = 19; // seems about right to ensure all colors
                // are noticeably different from their neighbors in this scale.

        
        var modNum = (i%intNum);
        var divNum = ~~(i/intNum);

        var modDivNumBy6 = (divNum%6)+1;
        var divCntBySteps = ~~(i/ (lumStep+1) );
        
        var int111Iterations = ~~((i)/(intNum*6));

        var intZero = (int111Iterations * lumStep)%256;
        var intValue = ((modNum * lumStep) + lumStart) % 256;

        // console.log('i: ' + i + ' -- modNum: ' + modNum + ' divNum: ' + divNum
        // + ' modDivNumBy6: ' + modDivNumBy6 + ' divCntBySteps: ' + divCntBySteps
        // + ' intZero: ' + intZero
        // + ' int: ' + intZero
        // + ' intCompleteIterations: ' + int111Iterations);

        var intR = intZero;
        var intG = intZero;
        var intB = intZero;

        if (modDivNumBy6 & parseInt("1", 2)) intR = intValue;
        if (modDivNumBy6 & parseInt("10", 2)) intG = intValue;
        if (modDivNumBy6 & parseInt("100", 2)) intB = intValue;

        var strReturn = 'rgb(' + intR + ',' + intG + ',' + intB + ')';


        return strReturn;

}


function createViewIcon(intAttribViewId)        {
        var strReturn = '<span class="circle" style="background:'
                + determineViewRGB_stepped(intAttribViewId) + ';">&nbsp;&nbsp;</span>';

        return strReturn;
}

</script>

<style>
        .circle{
                        width:8px;
                        height:8px;
                        border-radius:4px;
                        font-size:8px;
                        color:black;
                        line-height:8px;
                        text-align:right;
                        float:left;
        }
</style>
</head>
<body>
        <!-- It's close, but I think you can eyeball the difference between
                the first and second circles -->
        <script>
                document.write(createViewIcon(1) + createViewIcon(2)
                        + createViewIcon(400) + createViewIcon(3000));
        </script>
</body>

Just for fun, let's try it out.



EDIT: This apparently doesn't work in IE9 unless you're in IE7 mode. That's no fun. I need to go back to the page where I got the CSS code from, as at first it did work for me in IE9, but I'm not sure what compatibility settings I had going on there.

Labels: ,


posted by ruffin at 8/22/2012 02:26:00 PM
Thursday, August 09, 2012

Okay, maybe vba-ing your way from Excel files to raw SQL isn't the way most folks extract, transform, and load, but I like it okay when you get an Excel file of values.

This code is essentially the same as this jive from 2009, but I like that I've finally given up on adding a UserForm, naming it, adding a text box, naming it too, then stretching each until they look like a finished product.

Instead, I now just add a form, double-click a TextBox on there, and let this programmatically do the rest.

Option Explicit

Public Sub createSql()
Dim i As Integer
Dim intStart As Integer
Dim intEnd As Integer

Dim strInsertSql As String
Dim strUpdateSql As String
Dim strLine As String

Dim strOut As String


intStart = 2
intEnd = 963

i = intStart
While (Not "" = Cells(i, 1).Value) ' assuming there are no blanks in the first col
'While (i <= intEnd) ' if you'd rather hard-code


strLine = "INSERT INTO TABLE1 " & _
" (FIELD1, FIELD2) " & _
" VALUES " & _
" (" & _
CStr(Cells(i, 1).Value) & "," & _
CStr(Cells(i, 2).Value) & _
")"

strInsertSql = strInsertSql & strLine & "; -- " & (i - intStart + 1) & vbNewLine



strLine = "UPDATE TABLE2 SET " & _
"FIELD1 = '" & CStr(Cells(i, 1).Value) & "' " & _
"WHERE FIELD3 = '" & CStr(Cells(i, 2).Value) & "'; -- " & (i - intStart + 1)

strUpdateSql = strUpdateSql & strLine & "; -- " & (i - intStart + 1) & vbNewLine



i = i + 1
Wend


strOut = strInsertSql & vbNewLine & _
vbNewLine & _
"--------------------------------------------------" & vbNewLine & _
vbNewLine & _
strUpdateSql & vbNewLine & _
vbNewLine & _
"--------------------------------------------------" & vbNewLine & _
"--------------------------------------------------" & vbNewLine & _
vbNewLine



'============================================
' making this so I don't have to set up the
' danged userform and textbox any more
'============================================
UserForm1.Height = 800
UserForm1.Width = 1000
With UserForm1.TextBox1
.Top = 10
.Left = 10
.Height = UserForm1.Height - 40
.Width = UserForm1.Width - 20
.MultiLine = True
.ScrollBars = fmScrollBarsBoth
End With
'============================================
'============================================


UserForm1.TextBox1.Text = strOut
UserForm1.Show

End Sub

Labels: , , ,


posted by ruffin at 8/09/2012 01:13:00 PM
Wednesday, July 11, 2012

Scott Hanselman: Yeah. Iโ€™m looking at Jason Gormanโ€™s Twitter feed and he has a wonderful re- tweet from R. Tyler Croy who says โ€œLet's all argue about whether Haskell or Clojure is better while someone else ships a product with PHP and duct tape.โ€

Though that's a pretty funny (and wise) tweet, much of the rest of the podcast it comes from is pretty far from the mark. Ironic, as it's talking about how the irony that programmers are far from the [management] mark.

If AMD and Intel can agree to build processors to the same spec, why can't coders agree on CRUD? RLY? That's a valid parallel? Look, we know how to rebuild Microsoft Word, don't we? In fact, nothing rebuilds as well as code. Folks run EXACTLY the same thing everywhere the code's deployed.

Look, medical devices with software don't crash not [exclusively] because the programmers are wonderful, but because they know how to test. You don't need accredited programmers. You need accredited testing plans.

Scott Hanselman: I wonder if, you know, there's been books on software architecture that have drawn long and extended analogies with software design, with building design, and they do... I think that buildings and how you put up a building and these kinds of things, how do you put up a building without it collapsing, are pretty well understood. Is that because we've got 2,000 years of practice, and with software we've really only got maybe 50 to 100 years?

Oh, please. Construction workers can build buildings that don't fall down because little mistakes in my house don't stop it from compiling. Nobody was building my house the way they do it now 2000, 1000, even 400 years ago. That's a clown statement, bro.

Have these guys ever not built but owned a house? It's a mess of screw-ups and bugs. The hot water doesn't reach the kitchen sink quickly. One window is a different size than the rest. The commode leaks after two months. Light switches are unintuitive. Wiring is faulty and comes lose. The dryer duct is blocked. Years later, the exterior walls gain too much moisture.

The problem, of course, is what I hinted at earlier: Copying software is so easy software development teams forget it happens. Look in some cookie cutter neighborhood that has 5 plans built over and over. Now go into each of those houses and ask their owners (well, knock first if you're overly literal) how quickly the master constructors made each. Find out from the foreman what mistakes were made on each house, and how different those problems were from house to house.

And these guys were working from explicit plans. If I gave you the code to The Gimp and had you type it in all Compute! Gazette style, even if you weren't a programmer at all, it could work. Unlike construction, you need exactly zero experience to reproduce code beyond understanding how to read, type, and hit save a lot.

Every new app requires making new plans. Get it? Every new program, every new library, every new plugin is a brand new plan. And a brand new construction effort. And something that builds a new commode essentially from scratch. Programmers are architects, R&D workers, construction workers, and housing inspectors.

That's the reason every programmer feels more like an artist than a laborer. It's all new. They're not reproducing somebody else's clear plan, even when they amazingly have great mock-ups and test plans. If they had plans, anyone could hit copy & paste.

Houses require constant upkeep. So does code. Drop the metaphor. Or, better yet, get it right.

Labels: , ,


posted by ruffin at 7/11/2012 12:47:00 PM
Wednesday, May 30, 2012

Note that nothing said here should be taken as anything other than the ramblings of a madman.

From the apparently fairly seminal doc, Applications Programming in Smalltalk-80(TM): How to use Model-View-Controller (MVC) by Steve Burbeck, Ph.D.:

In the MVC paradigm the user input, the modeling of the external world, and the visual feedback to the user are explicitly separated and handled by three types of object, each specialized for its task. The view manages the graphical and/or textual output to the portion of the bitmapped display that is allocated to its application. The controller interprets the mouse and keyboard inputs from the user, commanding the model and/or the view to change as appropriate. Finally, the model manages the behavior and data of the application domain, responds to requests for information about its state (usually from the view), and responds to instructions to change state (usually from the controller). [emph mine]

I think that does it.  MVC means you've got a View (what the viewer sees), the Controller (controlling what happens to a user's input) and a Model (what encapsulates the data itself).  I'm going to try to go with that.

It's like 3-tier, but with two one-way roads going from your UI to your data management tier, one for what your app is showing the user, and another one-way road designed for what to do with your user's responses to what they see in the view.

That would make Fowler's image of MVC make more sense:

local copy of image


As well as his explanation of the "missing" line between View and Controller:

Essential dependencies between model, view, and controller. (I call this essential because in fact the view and controller do link to each other directly, but developers mostly don't use this fact.)

Note that the arrows are pointing the right way. The View does ask the Model for data to display. The Model does not push to the view.

That's the first time I've seen MVC described in a way that makes sense, so I'm latching on like a bit bull, right or not.

Ah, this makes more sense. It's one-way roads from the Model's point of view, but occasionally the Controller might yell at the View to save it a trip to the Model.

Communication Within The MVC Triad
...
The Passive Model

In the simplest case, it is not necessary for a model to make any provision whatever for participation in an MVC triad. A simple WYSIWYG text editor is a good example. The central property of such an editor is that you should always see the text as it would appear on paper. So the view clearly must be informed of each change to the text so that it can update its display. Yet the model (which we will assume is an instance of String) need not take responsibility for communicating the changes to the view because these changes occur only by requests from the user. The controller can assume responsibility for notifying the view of any changes because it interprets the user's requests. It could simply notify the view that something has changed -- the view could then request the current state of the string from its model -- or the controller could specify to the view what has changed. In either case, the string model is a completely passive holder of the string data manipulated by the view and the controller. [more mfn emph]


Though note that this only works on a locked resource in the Model, like the text editor hypothetical here. You can't do passive (well) in practice without very stringent locks, which is what the next section in the doc explains -- you need to have the View listening to the Model for changes, and event handling is born. Say someone else (an object other than its own Controller) changes the string that the text editor is editing -- the View needs to be alerted. And complex listening is born.

And since we can nest Views (a window holds multiple text boxes, eg, and both the Window and each text box has a View and a Controller) and since each needs to listen in on [different?] Models and Controllers in case of change (Controller says button for "Create new text doc" is pressed; wipe the View at the Window level and start over), what we've really got is an exceptionally finely channeled encapsulation for UI design that works well within, for instance, a 3-tiered setup. I think the bottom line is that MVC gets complicated quickly with a complicated UI, but to fully flesh it out causes some slick encapsulation and very easy maintenance. Afaict, IANAL, LMNOP.



In other vents, did I mention I hate the new Blogger interface? Hate it. It's so far from WYSIWYG that a 6 year-old could do better. What's wrong with the beautiful simplicity of the current Edit Html tab that I love, and that used to pop up with BlogThis? Seriously, I have to double check my View (har) every time I freakin post from BlogThis now. I HATE THE NEW BLOGGER INTERFACE. HATE HATE HATE HATE HATE. No kidding.

Labels: , , ,


posted by ruffin at 5/30/2012 10:03:00 AM

Separated Presentation:

Although the domain cannot call the presentation it's often necessary for the domain to notify the presentation if any changes occur. Observer is the usual solution to this problem. The domain fires an event which is observed the by presentation, the presentation then re-reads data from the domain as needed.

A good mental test to use to check you are using Separated Presentation is to imagine a completely different user interface. If you are writing a GUI imagine writing a command line interface for the same application. Ask yourself if anything would be duplicated between the GUI and command line presentation code - if it is then it's a good candidate for moving to the domain. [emph mine]

That's all well and good, but it seems to be reducing MVC (which is what I was reading about before I came to this page) to n-tier design (where n, surprisingly, is currently 2 -- which, when you're talking just GUI, I suppose is fine).

I'm pretty sure MVC is more convoluted than 3-tier design, which is what I usually use, but there I'm still reading.  Until then, this jive makes up a pretty good list of "best practices", especially the part I highlighted.  Being able to quickly remove from or add to your GUI without any change in data logic is the real test of [what I think is better called "encapsulation" -- why Fowler is re-monikering, I don't know] in your app's design.

Excellent, simplest case (give or take) logical refactoring of a non-tiered to properly tiered design follows the description on that page. Nearly required reading, kk?

Labels: , ,


posted by ruffin at 5/30/2012 09:40:00 AM
Thursday, May 03, 2012

The most annoying thing about setting up a WCF is the number of things that seem to work in the local testing server that'll explode in IIS. The local testing server that you can invoke with F5 is very lenient.

But before we get into the complicated stuff, a quick list of System-Provided Bindings from Microsoft:

WSHttpBinding
A secure and interoperable binding that is suitable for non-duplex service contracts.
BasicHttpBinding
A binding that is suitable for communicating with WS-Basic Profile conformant Web services, for example, ASP.NET Web services (ASMX)-based services. This binding uses HTTP as the transport and text/XML as the default message encoding.
WebHttpBinding
A binding used to configure endpoints for WCF Web services that are exposed through HTTP requests instead of SOAP messages.


Fair warning: I've done this three or four times now to make sure things work, but I haven't started from scratch on a new machine to run through the steps as I present them, here. Could be wonky somewhere. YMMV.

So let's start a WCF Service project. You select File >>> New Web Site >>>WCF Service. Save the new project in IIS's root folder.



That'll create a project with the file structure seen below:


Looking in Web.config, you'll see that, by default, this project has two endpoints. One is the MEX endpoint, which is nice, but not really the business end of things. The other is a wsHttpBinding. That's important, because, as we learned above, that expects to be called from a SOAP-compliant client.

If you try hitting F5 off the bat, it'll seemingly work, first going to a URL like this one:
http://localhost:50319/WCFService1/Service.svc

But if you try to view the GetData method, which is one of the two IService methods that Service.cs implemented by default, using a URL like this one:
http://localhost:50319/WCFService1/Service.svc/GetData

... you get no response, just a 400 error.

So it's worth saying that it's odd to have a SOAP client in my line of programming. You'd usually rather send out a very simple AJAX request to a URL from a web page to the WCF and receive some JSON back to parse in Javascript. The take-home is that we need to remove the wsHttpBinding (set up for SOAP) and set up webHttpBinding (ready for REST) instead.

The endpoints that Visual Studio inserts into web.config by default are below:
<endpoint address="" 
binding="wsHttpBinding" contract="IService">
<!--
Upon deployment, the following identity element should be
removed or replaced to reflect the identity under which the
deployed service runs. If removed, WCF will infer an
appropriate identity automatically.
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>

Our next step is to change that wsHttpBinding endpoint to one with webHttpBinding. I've also inserted the additional overhead of adding a JsonBehavior. Honestly, not sure what that's doing yet, but I think I want it.
<system.serviceModel>
<!-- serviceHostingEnvironment aspNetCompatibilityEnabled="true" / -->

<serviceHostingEnvironment aspNetCompatibilityEnabled="false" />
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<!-- To avoid disclosing metadata information, set
the value below to false and remove the
metadata endpoint above before deployment
-->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for
debugging purposes, set the value below to
true. Set to false before deployment to avoid
disclosing exception information
-->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="JsonBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>

<services>
<service name="Service" behaviorConfiguration="ServiceBehavior">
<endpoint address="" binding="webHttpBinding"
behaviorConfiguration="JsonBehavior" contract="IService">

<!-- original:
endpoint address=""
binding="wsHttpBinding" contract="IService" -->

<!--
Upon deployment, the following identity
element should be removed or replaced
to reflect the identity under which the
deployed service runs. If removed, WCF
will infer an appropriate identity
automatically.
-->
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>

(In case I've screwed up, the entire config is here.)

Again, switching from wsHttpBinding to webHttpBinding makes it so that we can use a URL to access the method. With wsHttpBinding, you'd have to have a SOAP client, which involves insane amounts of overhead for most of my applications.

There's more required than that, however. If you've got the same standard setup as I get in VS 2010, you've got two methods in the Service.cs file. One is pretty easy to set up to listen to query strings for its parameters;

[OperationContract]
[WebGet(RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.WrappedRequest)]
string GetData(int value);


Now, you should be able to nav to GetData and slap in a param of "?value=1231" and have that number repeat back to you with a URL like this:
http://localhost:50319/WCFService1/Service.svc/GetData?value=10

You'll see "You entered: 10" (with quotes) in the web page.


You can also leave the port off if you followed the instructions and created the dir in IIS' home dir and created the application using Internet Information Server (IIS) Manager. Go to your default web site, find your server's folder, right click, convert to application, and voila:



Unfortunately, the other method in the default project (GetDataUsingDataContract) is more complicated, as if you try to turn it into a GET-able method, your WCF Service will complain about the CompositeType hand-rolled datatype that's also part of the project VS 2010 dreams up for you.

[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);

You can't webget that because CompositeType isn't serializable.

Operation 'GetDataUsingDataContract' in contract 'IService' has a query variable named 'composite' of type 'CompositeType', but type 'CompositeType' is not convertible by 'QueryStringConverter'. Variables for UriTemplate query values must have types that can be converted by 'QueryStringConverter'.


Whoops. I'm not going to go into serializing to JSON right now. All things considered, that's an easy afterthought after this XML config wading.

So perhaps not the best composed, but that's today's lesson.

(A decent walkthrough of a slightly different way to go about this here.)

Labels: , , ,


posted by ruffin at 5/03/2012 03:52:00 PM

<< Older | Newer >>


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.