Coconut and Pineapple Mashed Sweet Potato (aka Yam) Casserole

A typical Thanksgiving dish is a sweet potato casserole made with mashed and spiced sweet potatoes topped with marshmallows and then baked. I’ve been making this variant using coconut and pineapple for topping (as well as coconut cream inside) for a few years. I’m doing it again this year, so I thought I’d post the recipe somewhere public.

Ingredients:

  • 3 large orange sweet potatoes (like garnet). I do mean large.
  • 1 package solid coconut cream mixed up in a cup or so of water (example).
  • 1/2 cup (or more if you like it sweeter) maple syrup (or other preferably liquid sweetener you prefer such as honey)
  • 1-2 teaspoons ground cinnamon (I ground fresh from sticks)
  • 1/2 teaspoon (or more) ground nutmeg (fresh ground)
  • 1/2 teaspoon (or more) ground all-spice (fresh)
  • 1/2 teaspoon (or more) ground cloves
  • 1/2 teaspoon (or more) ground coriander seeds
  • 1-2 cups dried coconut flakes
  • 1 pineapple cut up into 1 centimeter by 2 centimeter chunks or 1-2 cans of pineapple chunks that size

Steps:

  1. Peel sweet potatoes and cut up into smaller chunks. Boil until soft. Drain.
  2. Mash sweet potatoes with the reconstituted coconut cream, maple syrup and spices while still warm and place into a large casserole dish (or just mash in the dish like I did). Make sure it’s thoroughly mixed (no one wants a huge bite of clove except me).
  3. Cover the top with a thin layer of coconut flakes
  4. Cover that over with a solid layer of pineapple chunks.
  5. Just before baking, cover with rest of coconut flakes.
  6. Bake in 350F oven, uncovered, for 30-45 minutes (depending on how cool it got before baking).
  7. NOM. NOM.

Possible variations I’ve considered:

  • A heck of a lot more spice. I’m always wary of adding too much since these can be very strong spices.
  • We cut up a fresh pineapple for this, but if you used canned, you could drain some of the water and mix into the mash as substitue for some of the syrup or in addition.
  • Adding chunks of pineapple or bigger chunks of coconut throughout the mash.
  • Crazy layering: layer of mash, pineapple plus coconut layer, more mash, etc. Probably wouldn’t hold together though visibly and is probably equivalent to just adding pineapple and coconut to the mash.
  • Put casserole into small individual serving size dishes.

iOS Hello World With No Interface Builder or Storyboard

Inspired by Julia Evans who I’ve been following awhile and unabashedly posts about things she’s just learning, I’m going to start posting about some stuff I’m just learning! I might not know it all yet and might make mistakes!! This is exciting!!!

Anyway, right now I am trying to build a pretty simple iOS application. The app I’m aiming for is one I could probably build as a web app (in html/css/javascript) pretty fast, but learning Xcode, Objective-C and the entire toolchain seems like a useful thing to learn. I also don’t have a lot of time to really dig in so my time is fractured so starting with a “simple” app seems smart. Anyway, I first tried to use Xcode’s Storyboard and Interface Builder. Storyboard and Interface Builder are both graphical tools built into Xcode (Apple’s IDE for iOS & Mac development) that manage some xml configuration files that under the covers define the views and controls in your screens. I found this kind of infuriating. I have done UI work before so the concepts are not completely strange to me (I’ve done: web programming, client and server, a pebble app, and Windows MFC and GTK apps a long time ago). The problem with Storyboard was that immediately I didn’t understand how what I did in the GUI changed what appeared when I tried running my app. So really I need a map and guides to let me dig in without hiding things that will infuriate me. Maybe later I can use Storyboard.

It turns out, though, that people really want you to use Storyboard and Interface Builder. There don’t seem to be official samples that don’t use them (I picked half a dozen simple looking samples and they all seemed to have .xib or Storyboard files). After much google search term massaging (many of my searches turned up guides that assumed Interface Builder or Storyboard), I turned up a few posts that got me started. The first one got me some basic code so I could get grounded. The second was a great overview “map” of where I was going. The third told me how to remove the generated Storyboard (the new app templates with current Xcode always include a Storyboard).

A little while later, I had “Hello World” without using the GUI tools to construct the layout (and here I am a week or so later posting about it!) Since I had so much trouble finding what I needed, I thought I’d re-write it here. It’s also a form of rubber-duck learning: while I explain this into my editor (to post on the web), I’ll understand it better! On to the steps! First get an empty-ish project setup:

  1. Run Xcode (this is assuming you have it installed which I won’t go into).
  2. Create a new project. Pick Single View Application. Name it whatever.
  3. Delete the Storyboard file. Do this by clicking on it, then pressing the delete key.
  4. In “Supporting Files”, open Info.plist. Highlight the line that mentions the Storyboard.

Now we can go add code! Let’s look at our files. First, because we’re learning, let’s look at where “main” is (what will run first):

#import <UIKit/UIKit.h>
#import "AppDelegate.h"

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

I already had to go look up some stuff! Even though I know C and C++, I’ve never really looked at Objective-C before. One thing is Objective-C uses “@something” all over for various directives. Objective-C is clearly a stitched together monster of a language but I kind of like that. I assume @autoreleasepool is for some kind of memory management so I’m not worrying about it just yet. But NSStringFromClass([AppDelegate class]) …. huh. The other examples just had text like @"AppDelegate". What’s the difference? The @"AppDelegate" version is just constructing an NSString (versus a bare null-terminated string) with a particular class name. Turns out I want the latter way because it’s interrogating a class to get its name (call class on AppDelegate and construct an NSString from it). This means if I renamed AppDelegate to something else, I’d get a build error rather than a runtime error).

All this is doing is constructing some main framework app (I’d guess with an embedded event loop) that delegates a lot of work to my code. So what does AppDelegate do?

AppDelegate header file:

#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>
@end

The AppDelegate implementation file:

#import "AppDelegate.h"
#import "ViewController.h"

@interface AppDelegate ()
@end

@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
}
- (void)applicationWillTerminate:(UIApplication *)application {
}
@end

The examples I was looking at wanted to save off a reference to the window and the main controller, so I modified these two files. AppDelegate header:

#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) UIViewController *rootController;
@end

The modified AppDelegate implementation:

#import "AppDelegate.h"
#import "ViewController.h"

@interface AppDelegate ()
@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.rootController = [[ViewController alloc] init];

    [self.window addSubview:self.rootController.view];
    [self.window setRootViewController:self.rootController];
    
    [self.window makeKeyAndVisible];

    return YES;
}
// left out all the unmodified functions ...
@end

A lot to unpack here! First there’s a window created using the frame (bounding box) generated by asking the UIScreen class for the mainScreen and getting its bounds. The rootController is set with an instance of ViewController which is another class generated by Xcode for the simple project. Then, the window is told what view it has inside it and what its root view controller is. That second line I didn’t have initially and while the code “ran” I got an error and it wasn’t quite working right (the simulator didn’t show the simulated top status bar with time, battery, etc. in it). Clearly this matters somehow, although not critically. I’ll figure it out later! Finally, the ViewController. Its header I didn’t need to modify:

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
@end

The original version of this file didn’t have a lot going on:

#import "ViewController.h"

@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
@end

The default template assumes I’ll be using ‘nibs’ and Storyboard (nibs are files that reflect how you construct the UI in the Interface Builder to define your views). But I want to define the view myself in code. So I needed to modify it to support this:

#import "ViewController.h"

@interface ViewController ()
@end
@implementation ViewController
- (void)loadView {
    CGRect rect = [UIScreen mainScreen].applicationFrame;
    self.view = [[UIView alloc] initWithFrame:rect];
    self.view.backgroundColor = [UIColor whiteColor];
    
    UILabel *labelView = [[UILabel alloc] initWithFrame:CGRectMake(5,5,200,50)];
    labelView.text = @"Hello world!";
    labelView.textColor = [UIColor blackColor];
    [self.view addSubview:labelView];
}
// leaving out -viewDidLoad and -didReceiveMemoryWarning
@end

This constructs a really basic view that uses the entire space, sets the background color to white, then puts a label showing “Hello world!” on the screen. Looking this over while I type this up, I notice that in two places I’m asking for [UIScreen mainScreen] and doing something with it. Clearly this is probably not quite right and I’ll have to figure that out. But I have a working “hello world!” What did I learn?

  • Lots of basic Objective-C: how strings and properties are created, interfaces, implementation, sending messages (i.e. calling methods), etc.
  • Various UIKit APIs.
  • How to navigate the UIKit docs so I could figure out how to use UILabel and set colors.

And now, hopefully when someone searches the web for “iOS app hello world programmatic view” or something like that they find this useful!

GHC and feelings on being experienced

I went to my first Grace Hopper Celebration of Women in Computing a couple weeks ago. I graduated from school with a computer science degree in 2001 (and had a student programming job even before that). I’ve been working in industry ever since. Unsurprisingly, I had feelings about the experience. I spent most of the time there overwhelmed by all the people (not a fan of crowds and there were 11,000 attendees!). I talked to many excellent women, both young and more my age. I bonded with some of my women coworkers more than I had in the past. I felt a renewed sense of drive to do awesome things. But I was frustrated by how far we haven’t come and that GHC is necessary-useful at all. Many of the career and organizational change tracks I avoided — I’ve heard it all and don’t need to be reminded. But most of all I was glad to see so many different women in different places in life.

I graduated in 2001 with a B.S. in Computer Science (and a lot more math courses than strictly necessary due to a poorly planned double major in math). My program at the time required you to “apply” for the major after meeting introductory course requirements (calculus and introductory programming primarily). I remember sitting in the room where they welcomed us all to the major with around fifty people in the room. Only a couple of us were women. I didn’t know it at the time, but even then my program was clearly well below the norm for women. In 2001, almost 28% of CS degrees granted in the United States were to women (data in excel). But I didn’t care at the time. I was just excited to do do math and program computers. But this might be why I never learned about GHC until I moved to Seattle six years ago to take a job at Amazon which actually had a women in engineering group internally. I had few women role models or even peers before.

My career path has been strongly guided by a desire for security and stability. I grew up pretty poor. Getting a college degree was the first step to getting a good, stable job which for most of my career has been far more important than traditional concerns of career development, like learning new skills, taking risks or changing jobs for more money or better projects. Changing jobs is risky. Sticking your nose out is risky. I think a lot of folks forget that not everyone has the same career goals or life path. Especially in big tech companies, we tend to focus a lot on college graduates with very similar backgrounds (middle class or better usually). In reality, a lot of tech job advice looks risky and low reward to someone who’s pretty glad they aren’t waiting tables at a diner for a living (I waited tables in college and I can’t say I really liked it). Why change jobs? Whatever minor (or major) irritants my job has, it’s probably the same somewhere else. Fortunately at most of my jobs I have been challenged. I got career development in spite of myself, but it wasn’t really because I was looking for it. Mostly I just wanted stability.

The last few years I’ve been a lot more conscious about my career and made some decisions that were a bit more risky. I changed teams in 2014, helped build a team starting with me and my manager to two dev teams that has shipped several features that are already doing well (in terms of practical business goals and user feedback). It was a risk and I definitely went into it feeling like I might fail. But I’m in a place where that felt okay to risk. And the outcome has been pretty good: I’ve learned a lot both technically and in terms of leadership. I got a promotion. But it’s also been really stressful. While doing that, I’ve also been doing a lot of things with the internal women in engineering group. This is also stressful. And, more other things at work (I like to call them “extracurriculars”). Meanwhile, I do have a partner and a toddler I care for quite a bit. So much stress! I joke about “leaning in” all the time, but it’s not a joke at all. It feels like running against a headwind.

So GHC triggered a lot of feelings about career and life goals. There just aren’t a lot of women who’ve been “around” as long as I have — and I’ve only been around 15 years depending on how you count. The last few years I’ve met a lot more women who have been around a while and that’s been great. GHC was dominated by two groups: many, many college students and large contingents from various tech companies. The latter were overwhelmingly younger than me which I couldn’t help but remind myself was because most of the older women had left tech. Some of the few career talks or panels I did go to tended towards being positive to the detriment of being practical. I feel well past this advice and found it hard to not dismiss some of it as a pep talk. (And a couple of the plenary speakers should be at tech conferences actually attended by men because those are the people who have more power.)

I’m maybe a bit burned out about the “women in tech” topic right now.

But I got to meet so many interesting women! I met several women who are fairly senior in their careers and wanted to talk about what it’s like to work where I do. (My answer briefly: it’s not rainbows and puppies but it’s workable and make sure you ask a lot of questions about the team and organization.) I also met some young women still in school worried if they had enough resumes but so excited to be there (why exactly do we still have print resumes?). I got to have excited, expansive, “what if?” conversations with multiple (multiple!) women who are awesome (in different ways). I got to meet (or re-meet) women I don’t know well. I saw technical talks by women at many different places in their careers and life (internet of things despite the silly name is really cool and I want to do more in it!)

In short, I got to see women living a variety of lives and not constrained (or appearing to be constrained) by one way of being a “woman in tech”. I got to see women who clearly just don’t bother with thankless emotional labor in service of increasing the number of “women in tech”. And I got to see women who do some but have learned to be choosy and (maybe) avoid burnout. Because I’ve frankly probably been a bit burnt out.

I’ve been pretty pensive since GHC. And wildly enthusiastic at other times. What do I want to do next? Where am I going 2-3 years from now? Where do I want to be in ten years? What does it mean for my family? What’s important to me besides having a well-paying, stable job? Shouldn’t I go work on something more meaningful (thinking long-term) if I can? What’s that going to be? What should I be doing now to make that happen? How do I manage myself day to day and week to week to not lose sight on that? How do I manage my own emotions so I can be committed and happy with how I spend a third plus of my life?

In other words, I have choice unlike many people who grew up like I did. And that’s a weird and strangely uncomfortable place for me.