Tuesday, August 15, 2017

ArtAtomic - 2D Geometry and Color library for JavaSript


When doing 2D graphics there are a few patterns you'll use all the time - points, rectangles, matrices, etc... To make 2D geometry and colors easy to work with, use ArtAtomic. The atomic data-types include: Point, Color, Matrix, Rectangle and Perimeter. ArtAtomic provides the foundation for other ArtSuite libraries including ArtEngine, ArtText and ArtBitmap.

Quick Example

p1      = point 10,  20
offset  = point 300, 400
area    = rect  200, 200, 1000, 500

area.contains p1                       # false
area.contains p1.add offset            # true!

red   = rgbColor #f00
blue  = red.withHue 2/3
white = red.withSat 0
red2  = hslColor 0, 1, 1
red3  = hslColor 1, 1, 1
red2.eq red                            # true!
red3.eq red                            # true!

halfTransparentRed = rgbColor #f007
halfTransparentRed.eq red.withAlpha .5 # true!

What Does Atomic Mean?

These classes are designed to be used in a pure-functional way. Never modify their properties. Instead, use their methods to generate new objects.

HOWEVER, JavaScript performance requires minimizing the number of objects you create. As-such, there are some ways to end-run the pure-functional nature of ArtAtomic by re-using existing same-type objects. This should only be done in places where you can prove that there are no other references to the object you are reusing. In general, the way this works in ArtAtomic is some methods take an extra, optional argument called "into" which lets you specify where the result should be placed. If that argument is not provided, "into" is set to a new object. In either case, "into" is the value returned from these functions.

Color (primary props: r, g, b, a)

The Color class provides many tools for manipulating colors. It works in RGBA and HSLA color-spaces. It supports converting to and from many standard string-formats: "#FFF" and "rgb(255, 255, 255)" for starters. 

One simple, cool example: rgbColor("#f00").withHue(2/3) == "#00f"

Point (primary props: x, y)

Points are the foundation of any geometry framework. These points are all 2D: x & y. This library lets you perform math and comparisons on points: point(1, 2).add(point(3,4)).average(). You can treat these points as vectors: dot and cross-products are: point1.dot(point2) or point1.cross(point2). Also, point2.magnitude will return the magnitude of a point.

Rectangle (primary props: x, y, w, h)

Rectangles specify their upper-left-hand corner and their width and height. Strictly speaking, the upper-left point is included in the rectangle and the lower-right point is not: rect(1,2,3,4).contains(point 1, 2) - true, but rect(1,2,3,4).contains(point 4, 6) is false.

Rectangle has many useful methods in addition to basic arithmetic and comparison including: union, intersection, cutout, nearestInsidePoint and more...

Matrix (primary props: tx, ty, sx, sy, shx, shy)

This 2D matrix library provides all the standard matrix operations: translate, scale, rotate, mul(tiply), invert and, most importantly, myMatrix.transform(myPoint) => myTransformedPoint. 

Perimeter (primary props: left, right, top, bottom)

The most recent addition to ArtAtomic is Perimeter. This is primarily used to express margins and padding in ArtEngine. Currently there are only a few additional methods on top of the standard arithmetic and comparison operations.

ArtAtomic Resources

Learn more on the wiki: ArtAtomic Wiki

Monday, March 20, 2017

Saturday, January 28, 2017

Your SOUP is Leaking - Crafting Acronyms

I've been making a lot of acronyms lately. Acronyms can help us think about, remember and communicate a concept. A good acronym, like a good word, can fundamentally change the way we understand the world. 

Until recently, civilization didn't have a word for blue. It's true! Business Insider has a surprisingly good article about how no ancient civilization had a word for blue. Even more surprising, it might be true that civilizations without a word for blue couldn't even see blue - at a conscious level. They had the same hardware, but their software wasn't tuned to thinking about blue, and therefor they couldn't see it. 

Words enable thinking and communicating. Without the word blue, how would you describe the color? You might say "it's the color of the sky," but as the lovely children's book Sky Color demonstrates, the sky has colors across the spectrum. You might point to other blue things, but it turns out in ancient cultures basically there weren't any blue things. Blue is extremely rare in nature, and no-one is going to build something they don't have a concept of.


Concepts are powerful. Concepts embodied in a word, more-so.


Picking a Good Acronym

Really, we are talking about making up a good word or a good, new-use of a word for a concept. Acronyms work because they provide a built-in mnemonic for remembering them. I find the stickiest acronyms reuse existing words such that the other meanings of that word somehow reinforce the new concept.


Traits of a good acronym:
  • Pronounceable - if you want people to use it, they have to be able to say it
  • Real Word, preferably with related meaning - the stickiest acronyms use this (see above)
  • Fun or Funny - make it playful so people play with it - and start using it
  • Phonetic - if it isn't a real word, make sure it's a least phonetic. If someone hears it, they should be able to write it down without having it spelled out.
  • Short - shorter == stickier
  • Clear Expansion - the expansion should be clear and succinct. It should embody the essence of the new concept.
  • Try not to  Force Letters - sometimes the expansion is 'forced' to match the acronym. Letters are left out or added to make it work. The more forced, the less sticky. 

My Favorite Case Study


  • Real word
  • Super clear expansion
  • Real-world wet vs dry makes a nice analogy between code with and without repetition respectively.
  • When I first ran across DRY maybe 7 years ago, I went "Yeah!!! Someone summed up a vague concept in my head succinctly and clearly!" Ever since it's become my daily mantra and a significant influence in my ever-deepening understanding of programming.

My Acronyms


  • ZEN code has many traits in common with Zen-buddhism - serene, minimal
  • The expansion very precisely describes the programming pattern.
  • In both these ways and the fact it's pronounceable and spellable, it beats out YAGNI.

EVA - Essence Vs Artifact
  • Pronounceable, short, phonetic, though not a real word
  • Clear expansion
  • I find it fun and pleasant. Maybe I've seen WALLE too many times. I always hear his voice when I see the word.

POET - Principle of Exposure and Transparency
  • Real word. One might say good poetry is both clear and has depth. This concept is mostly about clarity, but the concept itself has a lot of depth. I know that's a little forced, but every synergy between the real-word and the concept gives the acronym lift.
  • I forced 1 letter - the 'of' is included, but the 'and' is not.
  • Including the word 'principle' could be considered another form of forcing. All these acronyms are in some form 'principles' - why is this one so special it needs to be included explicitly? Nothing. It just works!

NINO - Natural-In, Natural-Out
  • Pronounceable, short, phonetic
  • Expansion suggests a question - what is 'natural'? This is key to the concept - get thinking about how to make our UIs as natural as possible for humans. There is no definitive answer what that means.
  • Oh so much better than WYSIWYG as an acronym. 
  • The NINO concept is bigger - a superset of WYSIWYG.

WLC - Write Less Code
  • NOT pronounceable or phonetic - I hesitate using the acronym at all. However...
  • The expansion is awesome. It's super catchy and a hugely important concept. I use it all the time in my presentations. 
  • WLC just becomes a shorthand. I -never- attempt to pronounce the acronym. ('wulk'? - ick)

SOUPShowing Our Undies Programming
  • expansion is funny
  • real-word
  • real-soup is not a good thing when mixed with computers, and it isn't when mixed with code
  • The SOUP concept is a form of leaky-abstractions - and real soup can leak :). If you've used up 'your undies are showing' jokes, you might say to a coworker 'your SOUP is leaking.' It's a nice synergy.

Go!

Go MUYOA (Make Up Your Own Acronyms)! If you've got a concept you are revisiting regularly, try figuring out a way to capture it in a word. Who knows, it could catch on and the world could see blue for the first time!

Wednesday, January 25, 2017

SOUP - Showing-Our-Undies vs Conscious-Programming

Have you ever thought, while using an application, that it should be doing this work for you? A great example is reload buttons, in particular the pull-down-to-reload UI on many mobile apps. Why should the user need to tell the app when to update its data? The app should know and automatically update its data the instant it changes.

The problem is programmers getting lazy. Programming is hard. Programming problems can be hard. And sometimes... Programmers just push the problem onto the user - they ask the user to press a reload button instead of automatically updating.

This mentality is ubiquitous. Apps everywhere expose the inner problems of the program that are irrelevant to the user. We programmers get lazy and let our undies hang out in public.

SOUP is about Quality

Laziness is not the only cause of SOUP. Real-world budget constraints and the need to get-to-market lead to cutting quality. Hard problems to solve in programming often get pushed off to the user with the conscious or unconscious justification that it's 'easy for the user to do.'

Presenting the user with an amazingly-well-designed app is the key to success, and yet it's easy for us to forget that and let 'real-world' pressures cause us to degrade the user's experience. This destroys the magic and results in a second-rate app that is much more likely to fail.

SOUP is about Culture and Normalization

The other major problem is culture. We become normalized to a certain kind of app working a certain way. We forget to stop and ask if there is a better way for the user to accomplish their task. I think spreadsheets are in this rut. Fundamentally they haven't changed since the original Visicalc. They are great for getting started, but once you have more than a few dozen cells with calculations, they become a bear to use. 

Programming tools are always improving. Often something that was hard in the 1970s is now easy in the 2010s. However, many UIs are still written as-if we were using the tools of the '70s, '80s or '90s.

Conscious Programming

The term conscious-blah is used for many things these days: conscious-living, conscious-eating, conscious-parenting, etc. Open up google and type in 'conscious a' or any other letter of the alphabet and you'll see some similar terms show up. 

I think all of these mean the same basic thing. We can't be conscious of everything all the time, but we can shine the light of consciousness on as many things as we can think of for a brief time each. It's about creating a practice of revising our assumptions, actions and thought processes periodically to make sure they still hold true. My life motto sums this up nicely: question everything

I advocate for conscious-programming because there are many unfounded assumptions in programming - many artifacts which distract us from the essence of what we are trying to do. My post on Amazingly Great Design has some ideas on how to effectively focus on the essence of delivering value to users and cut through the jungle of artifacts.

Tuesday, January 3, 2017

Beyond CORS

The Problem with CORS

The App Principle: A web page is an application. In order for web pages to remain relevant in an app-driven world, web-apps must be able to do anything native apps can.

CORS breaks this principle. It restricts the information a web-app can fetch from the internet, and even if you are allowed to fetch it, it sometimes restricts what you can do with that information. Native Apps can fetch anything from the internet and do anything with it.

CORS has other problems as well. It isn’t consistently implemented across browsers. Safari 9.x interprets HTMLImage.crossOrigin differently from other browsers. CORS setup is difficult to get right and therefor it’s easy to get it wrong and actually create exactly the vulnerabilities CORS is supposed to prevent. Last, CORS returns extremely opaque errors.

Why Does CORS Exist?

I’ve been trying to understand this question for a year. My best understanding is, before CORS, web-apps were even more restricted. CORS opens up cross-domain access while preventing hacks such as:

  1. Badwebsite.com attempts to fetch your emails from gmail.com; if you are logged in with gmail.com, without cors, it could do this!
  2. CORS “taint” - I just don’t know. Is this a way to appease copyright holders? It doesn’t really prevent anything since Native Apps aren’t restricted in this way. Further, all you have to do is set up a basic web-proxy server and your Web-App could do anything with any image on the web. I have not been able to determine any legitimate reason for the existence of 'taint.'

CORS is the Wrong Answer

Reason #1 above is the main reason for CORS. It is legitimate from a certain perspective. There is a potential vulnerability, but it is the wrong solution. The problem is when “badwebsite.com” attempts to contact “gmail.com” it gets to freely use your cookies authenticated with gmail.com. This is something Native-Apps cannot do, so why should a web-page get to do this? And yet IT CAN - without CORS restrictions. This is insane. It’s like logging into the Gmail Native App on your phone , and then switching to MyMalicousApp and allowing it to send requests to Gmail using your login information from the Gmail app.

Beyond CORS - Sandboxed Cookies

It is relatively easy to solve the CORS problem now that we have separated the essence from the artifacts. We just need a way to allow websites to make external requests without giving them access to all the client’s cookies. The answer is to treat each webpage as a separate, isolated application with its own, sandboxed set of cookies for all the other webpages it communicates with.

I propose we add an option to XMLHttpRequest called ‘useSandboxedCookies’. When true, any web-application for a given domain is now allowed to make any request to any url - just like any native app could. However, all cookies used in those requests are local to that web application. This is exactly how native-apps work.

Example:

  • Alice logs into Gmail.com directly.
  • Then she goes to MyWebsite.com, which attempts a GET from Gmail.com
  • The cookies in the GET request to gmail.com are empty - the GET originated in the sandboxed cookie-space of the MyWebsite.com app.
  • So, even though Alice is logged into Gmail.com in one tab, in the MyWebsite.com tab, requests to Gmail.com appear to be coming from a new session.

This solution doesn’t actually do anything you can’t already do with CORS. All you need to do is set up a proxy server (example: corsproxy), which returns all the right CORS headers, and any website can fetch data from anywhere on the net, taint-free. However, setting up a proxy is not generally an option because it is costly, inefficient and not library-friendly. We need a client-side solution like the one above.

  • We should do away with the Taint concept entirely. It doesn't achieve anything useful, but it creates a lot of developer pain. Therefor, Sandboxed-cookie-requests should never return tainted objects.

Safe, Cross-Web-App Communication

My useSandboxedCookies proposal above solves 99% of the CORS problem. Since it could be added to the HTML spec in addition to CORS, we could stop there. However, there is another use-case that my proposal prevents but CORS allows, however poorly.

There are legitimate reasons why MyGoodWebsite might want to access Gmail.com using Alice's logged in credentials, and Gmail.com may want to allow it. For example, Gmail.com may want to offer a ‘log in with Gmail’ feature to third-party web apps. My proposal above prevents this since the only client-side code allowed to access Alice's Gmail.com cookies is Gmail.com’s code itself.

We need a reliable way for two client-side apps to communicate with each other. To do this, we can add a relatively simple extension to the postMessage API: allow postMessage to post a message to a URL. When this happens, the browser fetches data from the specified URL to initialize a headless client-side javascript session. That session can then send and respond to postMessages with other client-side web apps.

In the example above, MyGoodWebsite could postMessage to gmail.com/api.js. Once the gmail app loads, it sends back a postMessage that it is ready. Then MyGoodWebsite can use Gmail’s custom API for authentication. The gmail.com/api.js app can then use the user’s already-authenticated gmail.com cookies to communicate with the gmail.com servers and authenticate the third-party app.

Recap

I've outlined two proposals which superscede CORS and solve its problems:

  • Sandboxed Cookies: allow a web-app to safely fetch data from anywhere on the web with a simple client-side flag set per request, without any painful 'tainting.' Tainting is depricated.
  • PostMessage to URL: Allow any web-app to start any other for the purpose of safe communication and safe use of authenticated cookie credentials.

I have wasted way too many hours on CORS over the past few years, and I'm sure I'm not the only one. These proposals are simple to use and implement. They would open the web up to the web itself, instead of just native apps.

Does anyone know how to get the attention of the HTML5 standards committee?