Samuel Goodwin

94 posts Samuel Goodwin
  1. Ghost's API

    Ghost is a blogging platform written in Node JS that was released a few years ago after a successful Kickstarter campaign. They promised a blogging platform without all the complications of Wordpress and even partnered with companies like Digital Ocean to make it easy for users to try and use. One of the promises of Ghost was that the web admin tool was built using an API from day one rather than adding an API after the fact. It used EmberJS and provided a fairly nice web interface. The API, however, remained private and only worked with this JS front-end. Years later, they added the ability for third party clients to authenticate and access the API, but it was still a private API and therefore subject to change whenever they felt like it. Last year, they even released a "desktop" client. It made use of Electron to essentially

    Samuel Goodwin
  2. The Case of the Broken Buttons

    On a client project the other day, I spent most of the day tracking down a rather serious bug. All UIBarButtonItems were nearly un-tappable on iOS 11. These were not especially crafty buttons, most of them were using either an icon of reasonable size or a title. Some were even using the system standard items. None of them worked. Icons were un-tappable, back buttons were only tappable on the edges. All users on iOS 11 were left out in the cold and would not be happy. Instantly I assumed there was some clever code hiding somewhere that was causing the problem. I searched the project (this was a fairly new client so I did not know all of what lurked there) for subclasses of UINavigationController and UINavigationBar. I looked for categories and extensions on UIBarButtonItem as well as the navigation classes. I even assumed the problem was with one of

    Samuel Goodwin
  3. How To Write IRC: Part 6

    This is a continuation of the article published yesterday: How To Write IRC: Part 5 Framework-ification After all this work, it was time to make the actual framework. I started by making a new project with the Cocoa Framework template and copying over the important files from my demo project. Next, I setup support for Carthage for people to bring this into their own apps. I could support Cocoapods as well, but I don't especially care, so I left that for someone to submit a pull request to add. Supporting Carthage was fairly straightforward, I followed the directions on their front page without much of an issue. One minor thing I ran into: because I was developing this using the latest Xcode Beta and not normal Xcode, I needed to use xcode-select to tell command-line xcodebuild (which Carthage uses) to use my beta version of Xcode instead of the default.

    Samuel Goodwin
  4. How To Write IRC: Part 5

    This is a continuation of the article published yesterday: How To Write IRC: Part 4 More Tests! Next larger feature I wanted to test was joining a channel. As I planned before, joining a channel should create a new object to give developers a way to interact. For this I modified the first test I wrote which had the basic parts laid out already. It didn't really test anything anyway, so I made it do something useful. func testJoiningAChannel() { let user = IRCUser(username: "sgoodwin", realName: "Samuel Goodwin", nick: "mukman") let server = IRCServer.connect("127.0.0.1", port: 6667, user: user, session: fakeSession) let channel = server.join("clearlyafakechannel") struct ChannelDelegate: IRCChannelDelegate { let expectation = XCTestExpectation(description: "Any message receieved") func didReceieveMessage(_ channel: IRCChannel, message: String) { expectation.fulfill() } } let channelDelegate = ChannelDelegate() channel.delegate = channelDelegate wait(for: [channelDelegate.expectation], timeout: 1.

    Samuel Goodwin
  5. How to Write IRC: Part 4

    This is a continuation of the article published yesterday: How To Write IRC: Part 3 Async Integration Testing Some of you might be reading along and think to yourself, "This guy hasn't tested anything! He doesn't assert anything. What kind of lies is he trying to sell?". To that I say, "Give me a minute, it gets better". One of the nice things about code is that nothing you write really needs to be permanent. Especially when you're starting a thing, it's fine if you have to change it a bunch. You don't need to know exactly what you're going to do right when you start. That would be boring. The very next thing I wrote was an actual test with actual assertions. func testServerDelegateGetsServerMessages() { let user = IRCUser(username: "sgoodwin", realName: "Samuel Goodwin", nick: "mukman") let server = IRCServer.connect("

    Samuel Goodwin