< prev 22 Dec 2017 to 14 Nov 2014 next >

Posts tagged 'learning'

  • git is like algebra

    There are topics we research once in a while to confirm that they're still bad ideas.

    I jokingly recall that my dad tries cooking eggplant once every two years to see if he still dislikes it. The last time I was around, we both ate a single slice of a rather appealing looking Eggplant Parmesan, looked at each other, and threw the rest of the tray away.

    Today, that mistake is git-submodules. It makes sense that we'd want to have code that can be used together but that is upgraded at different rates! And, in all honesty, there are plenty of solutions for this kind of problem that don't demand submodules. A typical ruby solution would be to build a gem and either publish it on rubygems, or point the Gemfile to a known git repo; I imagine most other packaging systems offer a similar solution.

    Back at Demyst, we used a monorepo, and while I can't decide offhand if that was the right decision, it was skill-appropriate for our situation, and we made it work.

    For a time we considered using submodules, but our CTO waved me off and so I didn't do more than some perfunctory research into them at the time.

    Today, I thought I'd look at them again, and (as you do), I ended up reading git-scm.

    (For context, I'm also knees-deep in writing the book at the moment.)

    Looking at the description of submodules, there's … nothing at all worrying here. As one person on HackerNews described it, "so the problem with submodules is that they don't work if you don't use them right."

    While writing the book recently, I wondered how to explain to readers how to get over the biggest hump in algebra. And it occurred to me: most problems with git are the same problems people face when learning algebra.

    Consider this: algebra is a way of describing highly abstract situations using symbolic representations. We wish to accomplish some task, so we convert the relevant information to symbols, then manipulate those symbols until we recognize that we've achieved a result. We then translate the result back into the language of the problem.

    Students who never grasp algebra tend to view it as a collection of recipes. They find a formula that seems to fit their situation, plug numbers in, manipulate by rote, and hope for the best.

    I think we've all met developers who do this with git. (Some of us are these developers.) The trouble in both situations is that we don't know what we're trying to accomplish; the canonical "developer who doesn't understand git" treats commits as a secretary treats saving in Microsoft Word: something to be done periodically to ensure you don't lose work. git add .; git commit -m "Update". All that fits in their model of the world is "this is a way to save my progress and make it available to other developers."

    Which can be fine, but it means that in a typical repo the value of using git at all can be lost in the mix1.

    For math students and developers, the solutions are probably similar. Motivate the core abstractions, then practice applying them until a) they can see that the abstractions relate to their real-world problems and b) the actions they take mean things and aren't just arcane spells.

    The syntax of algebra, and the syntax of git, can be confused as the goal itself, when in truth the syntax is a means; the goal itself is abstract, and without having a pre-existing understanding of what you're trying to accomplish, both skills will always seem like magic.

    1. I for one am a huge fan of patch mode. Even when I'm editing files that span concerns, I'll use git add -p to triage the files into multiple thematically related commits so that when it comes time to review the history of the codebase, I can remember why I did that particular stupid thing. 

  • Week 9 Day 2 - Movin' right along

    Today was the .css assessment, and after working late (and falling asleep while working a few times) and doing the practice twice, then studying the solutions last night and this morning, I kicked ass.

    To summarize: good design often has a logic, and good instructors are consistent, almost without fail. If there are exceptions, they are for a good reason - your instructor is working at the forefront of the field and the rules aren't established, the design language you're working with has some foibles that you have to work around.

    In our case, I've managed to pick up on and benefit from the design habits of our CSS specialist, Jonathan, and have slowly been trying to incorporate them into my own design language. For instance, set consistent (and generous) margins/padding, keep visual space symmetrical, tend to favor making item borders on the inside and container borders on the outside, … and so forth. I haven't built all of this into my site yet—it still looks like baby's first webpage, although thankfully not as 90s as all that—but there are a lot of things coming together very quickly.

    Case in point: investing in figuring out backbone means that I've basically added three full collections, three full models, and half a dozen views to my app today alone. I also added two utility … packages? files? to my app that enable some neat stuff, one that makes my life easier, and another that enables a pretty cool "live search" feature to the website.

    Yeah, it's all pretty silly overall—I'm reinventing the wheel—but I know why and how I'm reinventing the wheel here, which is okay by me.

    There's very little of what I'm doing that is really challenging now, which is okay after the weekend. To use a workout metaphor, this is my plateau, where I'm consolidating gains before looking for more of a training effect. Again, I'm okay with that.

    Meanwhile, I'm able to explain to a lot of people what their code is doing wrong, or able to sort through arbitrary code and understand it pretty idiomatically; I'm much more confident with git and am aliasing my most common commands regularly, and can find my way around Atom like nothing.

    Wow, they have taught us something. :P

  • Week 6 Day 5 - The hero of the Greeks

    Today's partner: Max

    We spent the day implementing a lot of the things that are now standard on the modern web. Notably, modifying webpages while they're open without executing a page reload… and sending and receiving data in the background asynchronously by calling on the Homeric hero Ajax to carry our data.

    Wait, no. AJAX (Asynchronous JavaScript And JSON, originally XML) is indeed a means of sending and receiving data in the background while on a website, and it is somewhat heroic in terms of making the web work, but it's mostly a marketing term. What you're actually doing when you make an AJAX site is decoupling page rendering, moving the processes responsible for making your website look and operate onto the client side by leveraging small data transfers and pre-baked rendering operations that live on the client's computer.

    Someone else remarked that they would have felt capable of making a website (with server-side rendering) last week, but now they can't imagine not using AJAX, and I agree. The magic of the web today is being able to do things without having to transition, having access to all your tools through DOM elements appearing on page and stuff just getting whisked away to the cloud without your intervention. Everything feels snappier that way, and for someone like me (who gets angry with a 20ms lag while word processing) it's practically essential. I can already think of the sorts of things I want to implement and test with AJAXy techniques, but as we keep seeing, the class rapidly moves past "the coolest thing we know". The first week, I wanted to make an app in Ruby, then I realized what huge advantages SQL offers, then I thought Rails was the bee's knees, then I thought Javascript was the coolest thing we'd see… now I'm just waiting for the next thing.

    One thing, as an aside, that I can see is that there's virtue to practicing the things you're learning, but there's only so much to be gained. If the pet project you want to do is mostly nitpicking and trying to accomplish something the world has really moved past in the meantime, and all details of implementation… I can't necessarily see the virtue. There's always something to learn that will be maximally useful (of all the things you could be doing, and given your learning style) and it's not necessarily the obvious thing, or tying off the previous lesson.

    Learning relies on practice and scaffolding, but I'm getting the feeling that a lot of technologies require total comprehension of the basics (what's a closure? what's the difference between a proc and a lambda?), some understanding of the intermediate ideas, and total ownership of the thing that makes you money. To get to that point, you have to jump to the next thing while you still have the previous thing fresh in your mind, and have everything gel as a collection of "correct practices" and good habits, … and eventually you can make progress, actually breaking new ground after reaching the top of the (first) cliff. (The rest of the cliffs, of course, are "real" problems to be solved.)

    Learning all the nuance about everything is just pointless, though. There are just too many libraries and frameworks to learn back to front, and generally (successful) people build on what came before, and so the new thing is more or less like the old thing in structure and/or syntax.

    I can foresee, or imagine, programming always tickling the dopamine receptors in my brain because there's always some new framework… in the 50s, academic languages were the forefront; in the 60s it was all about business-specific languages; the 70s saw C gain popularity, with its general purpose systems programming capabilities… but there's not so much that's new in the history of computing. And there's never a point where you can sit still, content with what you know. Maybe that's a good thing.

  • Week 6 Day 1 - Red Alert! Asteroids inbound!

    Today's partner: Sai

    Today's project was second or third portfolio project1, Asteroids. We were playing with JavaScript and Canvas to draw the classic game on screen, and using an external key handler to bind input keystrokes to game functionality. A lot of ground covered in a short time, but I have to say it was pretty cool.

    Canvas is powerful and expressive—no less than I expect from an Apple-generated extension—and gives you the ability to do some very nice prettifying operations for cheap. JavaScript is, as usual, insane, but we were able to generate plenty of working code (once we figured out a couple issues with this, inheritance, and some other piddling details) in a reasonable amount of time.

    It doesn't even matter that I see other groups demonstrating more functionality in less time at this point. I'm learning a lot, we're learning a lot, and what we're producing meets my standards. I'm getting more familiar with the reference materials for the technologies we're using, and doing a lot of meta-learning in turn—learning how to find the more pertinent information from the MDN, for instance.

    This is the first project so far where I just really want to keep working on the code. Mostly this is because I can see where organic extensions can take place, for instance when drawing objects that are wrapping around the screen (what's the proper way to eliminate "popping" into and out of existence? Should I make the canvas larger while keeping the window the same size, or should I "clone" objects when they're within a certain range of the border and have the "clone" mirror the original's properties, or something else? Does canvas support a "toroidal space" mode?), but there's not a lot of time for that at the moment. I think I'll keep playing with it from time to time for the next couple weeks, but for now I'm obligated to tap out.

    I accidentally began reading the HTML tags guide, and it turns out we won't be doing the W6D2 curriculum until January… man, I want to do the lessons on semantics and document properties. The page layout/editing geek in me is drooling. Oh, well. Tomorrow's JQuery; time to get to work.

    1. depending on whether you view chess and ActiveRecordLite as both worth posting 

  • Week 2 Day 2 - The two hardest things in programming...

    … are naming things, cache invalidation, and off by one errors.

    Today's partner: Anthony

    Today was all Chess, all day.

    Actually, that's a lie. We did cover error handling in lecture and did a couple exercises (for about ten minutes; we figured that we'd do a proof of concept, then implement more error handling in chess.rb), but after about 10:30, we were coding the Chess class and its subclasses for about eight hours straight.

    It went well, in my mind. My partner is learning buckets of things, and he's been a real sport in terms of letting me show him how to do things quicker in Atom, pry, and git. We've been sure to make our code readable as we work, and test as we go - what we have now is readable, functional, and succinct. This is the kind of code I can begin to be proud of; lesson learned from the past couple days.

    Strangely, though, all this work results in about 300 lines of code, including whitespace… not a lot, right? Especially for the full-time output of two people. I'm sure that, in time, we'll be faster as a cohort, but this period is very focused on didactic activity: everyone has something to learn, if not from their partner, then from the code or documentation.

    The primary virtue of the Chess project, I think, is to see how you can best handle exceptions1, and to see how important it is to have well-defined roles contained in well-defined source files. It also helps to gain experience with git in different contexts, but I appreciate the simplicity of git's cognitive model, because basic use demands very little cognitive overhead.

    Other thoughts:

    • The office is moving over the weekend, to a more convenient location (for me) that is apparently about twice the size of the current place. Neat.

    • The coffee club is bootstrapping nicely; I'm going to send out a message to the group about a better ruleset.

    • I got three or four specific positive comments from people on various things I've tried to do to make people's lives easier. Feels good, man. (I mean, it's not why I do these things, but it's nice to know I'm not just emailing into the void.)

    • I wish I would have enough money to go out to lunch every day; some of the best conversations happen in the combinatoric randomness of lunch groupings.

    1. Instead of looping over input until it's valid, like I might have done in TI-86 BASIC, you embed your calls in a begin...rescue...retry...end block. 

  • Week 1 Day 4 - Applied telepathy

    Today's partner: Michael C. (since there are two)

    I think I adapt to things within three days. Today just felt normal, like what I should be doing with my life. I know it's going to get much harder before we finish, and I keep pushing things onto the stack to go into more depth on over the weekend—but there is already plenty to keep me busy. Life's going to be tough enough on its own, and I should probably be getting up early Saturday morning and diving right in. I may have to work remotely to get away from distractions (although this hasn't been as big a problem as I might have thought - Facebook and reddit just aren't very interesting to me now that I have a stack of things to think about).

    I am still not getting enough sleep, and it doesn't seem to actually affect my engagement or 'awareness' during the day. It's an awesome feeling.

    The highlights of the day were working with procs and, again, the big projects toward the end of the day. We were wrestling with understanding how to write our own versions of a couple Enumerable class methods (my_each, my_select, etc) but the breakthrough on this matter came when we tried to express the same things in "normal" ruby code and then translated that work into our functions.

    For instance, normally, to double all elements in an array, you might write

    1
    
    array.map { |i| i * 2 }
    

    When defining your own function to receive that proc, you can start with something done in the standard ruby function calls:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    def my_map(&prc)
      result = []
    
      self.each do |item|
        result << prc.call(item)
      end
    
      result
    end
    

    Simply replace "each" with "my_each" and you've basically re-created standard ruby functionality. I assume that, even if it's not now written this way, at some point the ruby "standard library" looked something like this (albeit with more error handling).

    My partner mentioned at the beginning of the day that he didn't really understand why you'd use procs, and within a half hour we both got it.

    The work on recursion was solid practice. The first example took ten minutes, the second five, and each one after was simply an exercise in analyzing the higher-level problem. Satisfying, and excellent practice/pedagogy, but nothing earth-shattering. :)

    make_change, the recursive method for taking a list of coin values (for instance, in the US, 25, 10, 5, and 1 for quarters, dimes, nickels, and pennies) as well as an amount that you're trying to target and yielding the list of coins you'd return in order to make the target amount with the minimum number of coins, was easy, then absolutely maddening. We managed to describe the core logic within a half hour - about one line every 90 seconds, go figure - and then took another half hour in order to track down a crazy edge-case bug that was killing most of our results.

    Constance looked at our code for a good ten minutes before we nailed down what was actually going wrong. We had a specific test case that broke the method quickly, a bunch of ghetto debug statements (p for the win!) and basically total awareness about the state of the internal variables, and we still struggled to find what was causing this failure.

    It turned out that there was a loop condition that this edge case was falling through, returning nil when our calling function was expecting an array. It was such a specific edge case that I should have seen earlier, but I kept looking in the wrong places for this, and the doubt caused by that sort of weakened my learning. I spent five minutes doubting each level of my knowledge, until finally I was doubting whether < actually means "less than". I'll definitely need more practice overall, and to develop more facility with debugger… and I've gained some specific respect for the challenges software maintainers face every day.

    WordChainer, today's "capstone", was a blast. The spec was thorough, and my partner and I basically spent fifteen minutes reading sections of it to one another and getting code into the editor. What a delight a properly detailed spec is! Too bad I'll probably never see one again in my life, unless I write it myself! ;)

    It took us about two hours to get a very respectable and pretty clean class for this portion, overshooting the end of class by a half hour. Remarkably, by the last hour, I wasn't sure which one of us was actually driving or navigating. Michael and I were basically on a single wavelength, and passing the keyboard back and forth was mostly a formality.

< prev 22 Dec 2017 to 14 Nov 2014 next >