Practice English Speaking&Listening with: Grindr Tech Talk: iOS Development with Test Driven Development

Normal
(0)
Difficulty: 0

Joel >> Im Joel Simkhai, Im the CEO, founder of Grindr. So I want to welcome

you guys to our talk tonight. Before I introduce Lukas, I just want to give you a little bit

of a background on Grindr. Weve just celebrated five years a few months ago and weve started here in Los Angeles.

Actually I was telling someone over in my living room for about two years and now weve been here in this office for

about a year now; a little less than that, and were global. We have about 5 million;

over, actually, over 5 million monthly users who go on at least once a month and on a daily

basis we have about a million and a half who use the service every day. Concurrent, were

about three hundred thousand, two hundred and fifty thousand users who on at any given

minute so a lot of traffic, a lot of usage, a lot of guys grinding, and this is global,

so this is not just here in the US, this is literally any country you could name, weve

got users there. And, this is, you know, it has to mean to you the power of the service.

Helping guys meet other guys seems to be very popular and we love to do that for them.

And the other kind of interesting fact is that were self funded, so we have

two versions of the app. We have a free version, and a subscription service. The free version

is ad supported and the subscription service is a monthly fee and so between those two

revenue streams we support the business here and you know, so weve never actually taken

any outside capital. And something else were very, very proud of is that were committed

to just creating great products and just doing a great thing for our users and for the team

here and not really worrying about investors and spending time on pitches and all these

other things. Were focused on creating great products. So with that quick background,

Id love to introduce Lukas Sliwka who is our VP of Engineering and the Head of Tech.

Lukas >> And I broke the microphone. Ok perfect. Welcome everybody. Today were

going to take a deeper dive into iOS development, Xcode specifically. Were going to focus

on a couple of areas that are very important to me. I joined Grindr six months ago.

Grindr experienced explosive growth as a company, and with that growth came a lot of development

in terms of backend systems, the frontend clients. And when youre in that mode when

youre growing so fast, a lot of times, youre kind of throwing things together

to keep up with other men, right? And it shows. It shows on our backend systems, it shows

on our frontend clients. The first talk I did about

two months ago, I talked about scalability, and so, during that talk I talked about what

it actually takes to support millions and millions of users, and thats not an easy thing.

Today were going to focus primarily on iOS side of things, and how you can actually

employ some of the strategies to best develop for your iOS clients.

So before we go on, I want to introduce a couple of people who are going

to be helping me along with this conversation. So, Id to introduce John King who is our

iOS developer and part of our iOS development team and also Rudi Hacopian who is our QA automation architect.

Before I go forward, I want to, kind of set the stage in terms of, you know, a lot of startups, a lot of applications

being built, you have maybe one guy, two guys, working on in a backroom, throwing things

together, right? Thats all great as long as you know frontend and backend and all the

ins and outs of scaling your application. There is a big difference between handling

a hundred users versus ten thousand users versus a hundred thousand users and the scale

goes on. I mean, as your organization grows, you need to have certain specialties, right?

However, when you look at startups, you need to stay agile to help people who are kind

of jacks of all trades but at the same time they are masters of few areas. So when youre

trying to set up a very successful startup or a company, a mid-sized company that is

very lean, you can do a lot with 15-20 people as long as these people are very passionate

about technology and you build a framework around them that allows them to innovate,

fail fast, learn, rinse and repeat. So well talk about some of that today.

So lets start by discussing, you know, what were going to talk about

today, so, specifically when it comes to iOS development, were going to talk about Test-driven

Development (TDD), were going to talk about Inversion of Control. Another name of that

is Dependency Injection. We specifically use Typhoon container for that. Were also going

to discuss Dependency Management powered by Cocoapods. Well talk about Burn, Build

and Release Pipeline and well talk about what makes a mature build and release pipeline

for a mature organization. I will like to set a low-context why I want to talk about

these things, alright? When youre a company and youre a startup, you want to have an

environment that enables innovation. My job here is to essentially build and engineer

an organization that promotes rapid change and rewards experimentation and thats not

an easy thing. As a developer, and if I could get a head counthow many developers in

the room, people who actually write code? So most of you. So you know what Im talking

about; how difficult it to be in organization that has production applications already supporting

revenue and thats locked in and at the same time youre trying to deliver all new

projects and at the same time technology is moving so fast, you want to experiment with

different technologies, possibly apply new things to improve things. Its a constant

battle between having a stable production environment that generates revenue, have a

development engineering environment where you can innovate and you can agree with the

product because product development also wants to deliver features so its a constant collaboration

and a constant negotiation between those different forces.

So what I want to talk about today is what it means to have a strong engineering

practice. When I started with Grindr six months ago, my main charter was to build a strong

engineering practice, and what I mean by that is, build a mature engineering practice that

essentially enables people and allows people to experiment, allows teams to experiment

and possibly fail fast, learn without affecting revenue, without affecting these core business

applications that are already running. Joel mentioned that we are

a mature business, that were making money. We have a lot of users in over 190 countries

around the world. Were processing massive traffic. Obviously, were not Facebook,

were not Yahoo or whatever, but you know, we deal with close to 200-500 messages per

second when it comes to chat. We talk about traffic like 250,000 RPMs to 500,000 RPMs.

We have days when we reach one million RPMs. Those are not easy things to withstand.

When youre designing your backend systems and also frontend clients then there will soon

be a lot of thought put in on how you orchestrate things. When it comes to the setting up of

a strong engineering practice, however, there are a couple of different components that

are a part of that and a lot of the stuff were going to talk about today are the

different building blocks of the overall picture. I just want to give you a context of why were doing it.

Why are we doing TDD, or why

are we using IOC container or why are we writing Unit Tests? Its not because its something

cool and someone else is doing it. Theyre doing it but theres a purpose behind it

and the purpose is to have that strong engineering practice. A strong engineering practice is

composed of three components, which are, processes, technology and people. I kind of touched already

on people and who we hire, who we want to be part of our team. Our engineering team

is very small, we have right now, probably fifteen to twenty people that are making this

whole thing happen. They are divided into various different functional areas so we have

standard dev ups, NOC type of practice, we have QA practice, we have architecture practice,

we have android, iOS development, we have backend practice. All these kinds of practices

have to come together in some way to create a product. We use agile and scrum for that.

I dont believe that any sort of modern software development should be using anything different.

I think that waterfall is dead. I am not afraid to say that. A lot of companies

are claiming that theyre agile and scrum. In my opinion, if you have a status meeting

in the morning that you callstandup’, that doesnt make you an agile organization.

Theres much more to that, theres going to be a separate tech talk on that where Im

going to take a deeper dive. But there are also other things, like Lean and Test-driven

Development and theres KISS, which is, ‘keep it simple, stupidor YAGNI, which

is, ‘youre not gonna need itor metrics. It all comes down to the fact that we want

to move very fast, we want to have a process in place that kind of sets a cadence to day-to-day

development but, as an engineering organization, we also have architectural principles in place

that are being governed and watched for in terms of how we build software.

In terms of technology, I am in a certain business, right? So I am enabling

the gay community to meet as fast as possible. Im not in the identity management business,

Im not in the business of building databases, Im not in the business of other engineering

aspects that are very cool for engineers to play with, however, thats not my core business.

So its very easy as an engineer to get caught up in the rabbit holes where – “oh

you know what, Im going to build my own stuff, right, because its cool.” Thats

not how we do things here. If were looking at the overall ecosystem of the Grindr application

as a whole, I want to channel the development effort into areas that havent been done

before and maybe there are no appliances or frameworks on the market to do them. I want

to make sure that I apply open source technologies, I buy whatever I need to buy, and I integrate

to build a strong solid platform that enables my team to do things that havent been done

before. I dont want to be in a business building cool geospatial algorithms

because there are plenty of companies that specialize in that. The databases that have open source

algorithms integrated inside them like Mongodb uses Google geospatial search.

I want to leverage that. I dont want to build that from scratch. When I joined Grindr, I looked

at the overall ecosystem. Theres a lot of things that were fixing because, over

the years, because were moving so fast, it was easier to build things from scratch

as opposed to maybe take a step backward, look at our architecture and design things

differently, so this year what were doing is were redesigning backend and were

completely revamping our system, the overall platform as well as building clients.

[13:50] Lukas >> When it comes to clients, its kind of the same thing, right? When

I look at Xcode and iOS development, iOS development just recently, last year, introduced the version 7

which brought, finally, unit testing tools and the ability to do things that havent

been around for a very long time. Its amazing to me, a lot of times when I talk to iOS developers

- I dont want to offend anybody - how special iOS and Xcode development is,

when I tell you that youre not special and the reason why youre not special is because software

engineering has been around for a very long time, and the concepts that have been introduced

into your ecosystem have been around for a very long time, and there is a reason for

that. The reason for that is because for a very long time weve done object oriented

programming and weve solved things through frameworks and microframeworks, and patterns

and those things should be applied. Xcode and iOS development is not different from

Java or any other type of language, so what I want to stress is that things that were

going to be talking about today are maybe new things that were introduced quite recently

into the iOS development ecosystem, but they have a very strong foundation in computer

science and the backing of at least 10 to 15, 20 years of object oriented development.

So, when I talk about frameworks, containers, automation, thats something

that we use here to essentially provide these tools, provide the technology, and the frameworks

and the process to allow our teams to experiment, learn, fail fast and do it better the next

time. We work in one week sprint cycles so that means that within five days, you need

to complete your development, you need to confront your definition of done which means

that regression testing needs to be done. You need to have a certain level of quality.

You cannot achieve that without automation and a certain level of maturity as an engineering shop.

So, lets talk aboutbefore we take the deeper dive, I wanted to throw some definitions out there for people who

have not done before. Test Driven development, have no doubts with dependency management,

dont know what the inversion of control is. Essentially, those are tools in our toolbag

that we can apply to make our development faster, better more robust and at the end

of the day we allow people to experiment with different framework, different technologies,

different approaches, without worrying if were going to put something in production

and thats going to bring me down and my revenue is going to stop. I want to have a

process in place as an engineering shop where I enable you guys to experiment, but in order

to do that I need some of these tools. [17:05] Lukas >> Im not going to go through

that, you guys can look it up on wiki. What I do want to do before we go into the code dive is

I want to take a brief moment to talk about inversion of control and testing.

So I set up essentially a very simple scenario, where I have a Class, ‘Grindr’,

that uses Grindr service and normally, if you dont have any serve containers

around that stuff you would just say, you know, I would instantiate my new Grindr class

and if Im referencing this Grindr service, I would have to have either in my constructor

or right here, some sort of way that Im instantiating this class or I can do it within

my business logic so its populated. When it comes to Inversion

of Control, its essentially a container that allows you to outsource, for the lack

of a better word, the business of creation and wiring classes together.

If I have two classes like this, my IOC container is essentially a way for me to create this class through

that container without me worrying about how thats done. Why its important, well

if Im doing test driven development, I want to have very atomic tests that are just

testing this particular component, which means I will have to, most likely, mock this service

and mock the responses of that service in order to have a valid test.

Very high level, Im not going to talk about more than that. I want to hand it off to John, whos going

to actually look at some code, show you how its done in Xcode, starting with Dependency Management using Cocoapods.

John >> Hey everybody. Luke was kind enough to introduce me, Im John King. I am an iOS developer here at Grindr.

Who here has not heard any of these concepts before tonight?

Fair enough. Alright, so the first thing I want to talk about is Cocoapods.

Oh! You can see what Im talking about, huh?

Awesome. So Cocoapods is what we use for dependency management for our Grindr project.

Cocoapods is in itself simply a Ruby gem we installed through terminal which will

keep a reference to all the various key repositories that are managed by Cocoapods and gives us

a really easy way to put them into our project.

To simply install it, we open our terminal and we gem-install Cocoapods just like you would in any Ruby gem.

Simple enough and if we go into Xcode we can look at the key part of a Cocoapod. So this is

called a pod file. A pod file is how we tell Cocoapods what dependencies we need for our project.

This can be opened up as any simple text file and thats exactly what this is.

Thats a text file with some glorified Ruby in it.

Lets go ahead and break this down for a bit. So you can see we have

a couple different build targets, if youre familiar with Xcode, that our entire workspace we build,

for each target we tell them what particular pods we need in order to build

this project for the winter. A pod is just a Cocoapod term for a framework that we use

within this project. So you see we have four various

targets, they use all very similar things. Next to them you see a version number.

This is an optional version number. If you omit the version number it will always install

the latest version. At any time you can run a different command called apod update

and it will take every dependency youre using and automatically update.

We dont have to worry about - oh has an update come out yet, have we received

an email about it, is it up for release? Lets go check and see if we have the latest versions

for everything that were using. We simply use a pod update.

For certain reasons we have frozen every particular pod were using. Were telling them this

is the version we want to use. Always go and get this version. Cocoapods uses a file called

a pod spec to give it all this information about how it might build in with your project.

For 90% of new developers this is something youll never have to work on unless youre

building a pod for someone else to use. Pod specs are there, you need to know they exist.

This pod file is the more important thing. There is a particular command that you see

here. Looks like a tilde arrow. We can actually do something like this if we so desired and

this would give us the latest men version of that file or of that pod, forgive me. So

lets say Im using Yama framework and they have a newIm sorry, go ahead

Q: [Inaudible] John >> Oh yeah, Im sorry.

Thatll work. Alright, hows that guys?

Apple says this is a good presentation size, its good enough for me. Alright, so, sorry, should have said something sooner guys.

So you see we have a tilde arrow here, we replace this with just our comma so instead of using the version weve given it,

itll use the latest men version which is the second number here available

to us. So lets say Yama framework as you see here arewe currently use 0.2 of it.

Lets say they have a new 1.0 release of it but theres also an 0.3, 0.1.0, it will

give us the latest second number that is available without moving to the next incremental. This

is useful if we want to keep using a similar version that we have but we are weary of using

the latest and greatest in case there are any bugs, in case it doesnt play right

with our archives for any reason. Its a handy little tool if youre using your little pod file.

So, this is the second most important part of the pod file for me. So we got a post install hook and this is our

chance to write and review code and do some things to help with integration with any of

these pods for example, we have a number of Xcode schemes that have their own particular

settings to help us build and maintain the project and often times just doing a pod install

- very basic - will not transfer these settings over to that, does not play nice. As I said

earlier, a lot of what we need in order to make these libraries build properly with us is in that pod spec file that Cocoapods uses.

Now, what Ive done here is a too much feinty Ruby Regex. All it does is take all those settings we need, copying

them into what well be using and tells us its done. Simple enough but you may

have any other use for that post install hook is catchall for we have downloaded, we have

installed the pods, we have integrated them into the project, do you need to do anything else?

Its important to know after you run a pod install, it will generate something called an Xcode workspace. For most people,

if you create a new Xcode project, it will be using something anxcproj’, an Xcode

project file. Similar to a vcproject in Visual Studio, but we need to use multiple projects

for this and what Cocoapods will do is automatically generate an Xcode workspace with everything

we need for it and that is the file we use from now on. You can forget about that Xcode project for time immemorial.

Before we move on does anyone want to ask any questions about Cocoapods, why you might use it, how it might be used?

Q: [Inaudible]

Excellent question. So Cocoapods has an awesome website, Cocoapods.org. Youd just like to find any other open framework.

It can be difficult to just know its out there and then once you find that its out there, whats a good one to use?

So I can go into Cocoapods.org and I can type in a generality of what I might be looking for when I type injasonkithere

and it tells me what pods are available for that and all I have to do is plug in what I find here into my pod file.

Q: [Inaudible]

How I pick one? Thats kind of up to the individual developer.

Its kind of like asking, ‘how do I determine what framework to use?’ Sometimes that just

comes with the individuals knowledge, sometimes it comes with trial and error. Its kind of a personal choice.

Lukas >> What I would suggest in those cases is that you do some sort of POCs, so if youre evaluating lets say three or

four different frameworks, what we tend to do is we come up before with an evaluation criteria,

so if you have ten things that you are looking for, you use a simple Excel spreadsheet.

On the left hand side you got your criteria. You list all your frameworks at the top and

then you can actually write little POCs using each and test the performance of whatever

and you can have actual metrics behind which one you wanna use.

Another thing you have to also look at is the [illegible] project how active it is.

How many people you have committing to it. So you have whatever, Github or whatever

repository you use its good to check how actively they are updating it, right?

Any other questions?

Q: [Inaudible]

Which parameters are we talking about?

Audience: [Inaudible]

Correct. Yeah, these are hardcoded version numbers saying that these are the version numbers we want to use. Do not use

anything later. Do not use anything older. Use only this version.

You have a choice to actually select something that will automatically load

the latest version that is better than this because, you know, what if they deprecated

some stuff and all of a sudden you do a build and youre stuff breaks. So, you need to

a entire ceremony when it comes to dependency libraries, when it comes to updating and its

usually a project that you want to schedule like, ‘ok theres a newer library for

this, lets actually have a user story in your agile port for that so you can actually

refresh it and test it for some stuff.

Very cool. Anybody else before we move on?

Awesome. So the next thing I would like to talk to you guys about is the Typhoon framework. The Typhoon framework

is the dependency injection or IOC container we use within Grindr. There are a couple of

IOC containers out there. You can find some small projects on Github but a lot of them

are either not being supported any more or have very little adoption but Typhoon seems to have risen to the top.

If you look online for any number of times for an IOC container for objective C, youll see Typhoons name was said

a number of times and it can be found at typhoonframework.org and from their website you can go their Github page.

There is also a Cocoapods for Typhoon in order to integrate it in.

Lets talk about some of the base things of using Typhoon.

The base part about going into Typhoon is you have these logical groupings called, ‘Assemblies’.

Assemblies are a group of related instance classes that can be used.

These can be later fed into our creation factory and they are how we will access them later

So you see Ive created a class here calledinpoint log assemblyand its derived from Typhoon assembly.

All assemblies are derived from Typhoon assembly and we return to type id and we have instances we will need to retrieve.various

Within our involuntation filewow this is big.

We return, we tell Typhoon, we give our class that what we need and then we have a chance to do some things to it before its returned.

So, for example, for the inpoint of log were telling it, ‘hey, this is the class we need and we need to inject it

with this property which is also shared within the assembly which is our inpoint of log entry

factory and were also setting the scope. Setting the scope is a really

important thing and it, kind of, can be difficult to understand for some things.

So there are four major types of scopes.

The first one is TyphoonScopePrototype, which, anytime we request this object, we

will get a brand new instance of it, everytime. No reviews.

The second and the default is the type object scope graph. If you do

not specify the scope, this is what it will do by default.

Object scope graph, object graph scope, rather, forgive me, is an interesting choice and Im a big fan of it.

Lets say Im in the view controller and I have some sort of delegate and theres an object we need to pass between them.

Lets say within our code base theres also another view controller and delegate and similar object so we dont

really have a singleton thats passed between but we wont have to try and pass the object

back and forth. With Typhoon object scope graph,

any time we request that object, we will receive the same one within a similar

frame of execution so lets say I have requested this view controller from Typhoon for whatever

reason and I am working within it doing some things and I request something else within

it, it will return me a new instance of that object.

Ive now gone somewhere else within this execution stack, and I request

that object again, its going to return me the same object, no different, the same

one. Now, Ive gone out of it and Ive gone into a new view controller to do something else.

It will get a new instance and its delegate will get the same instance of that.

Its very handy, very, very handy. The third type of scope you see here

on the board is TyphoonScopeSingleton. Does everyone know what a singleton is? One and only one. Awesome.

Theres also a fourth type called weak singleton. A weak singleton is just like a weak property that zeroes out if nobody has a reference to it.

Awesome. So lets talk about how these assemblies are used. Does anyone have any questions about the assembly before we move forward? Very cool.

Lukas >> Gimme a while, Ill change your resolution on the screen.

John >> Im not very good withcan I use built in retina display?

Lukas >> That should be a little bit better.

John >> Itll work. Alright, so you see here. Im initializing a Typhoon

component factory and Im feeding it a number of assemblies. You see, I haveuh, its

a little difficult to read here, forgive me. This is an array of various

assemblies we have within the project. And these are all the different assemblies it will manage.

Nows a good time. Uh, lets see.

Bear with me for just one moment.

So, the question comes up, ‘how do we access this factory at runtime,

when we want to retrieve things from it?’ So there is a protocol we

can use for our classes called TyphoonComponentFactoryAware. Whenever any of our instances get initialized

through Typhoon and we are TyphoonComponentFactoryAware, it will call setFactory on that object and

we now have a reference to whatever factory we are associated with and are gonna retrieve

anything from those assemblies, anything from our own assembly.

And its fantastic because all we have to do is cast the factory as an assembly and call the method as normal.

If we are not TyphoonComponentFactoryAware,

there is a convenience method called makeDefault and we now have a default factory that we

can access anywhere else. This is mainly used in legacy code.

Now I will touch on Typhoon again when we start talking about Unit Testing.

Does anyone have any questions about basic use of Typhoon? Very cool.

Alright, so who here has done Unit Testing in iOS?

Alright. Tell me, how easy did you find it to use?

Audience >> Just my first time soJohn >> Fair enough. How about you, sir?

How easy did you find Unit Testing to be done in Xcode?

Audience >> It sucks. John >> Little bit, yeah. Little bit.

So in order to do any Unit testing in iOS, we create an instance of a class called xctestcase. We derive from it,

we name it. We got a new class. Unlike other classes that

Xcode will create for you, we only have an implementation file. You can have a header

file but there is typically no need for it. There are one, two, three,

four, five major methods to know in any Unit Test environmentare in any Unit Test,

I should say. We have a class level setup.

And this is a chance to do any type of initialization before any tests

are run at the class level. This is run only once before all testing.

We then have an instance level setup which we run before any test is run

so this is our chance to setup any variables, get the environment a certain way and itll

be run once for every test case and then it will run any method that begins with the word,

lower casetest’. Objective C is definitely

coating my convention and this is a good example of that.

It will go through any method that begins with the word, ‘test’, no

matter how it ends in range of those. And then after each test it

will run an instance level teardown which is our chance to clean up after ourselves

and after all tests are run, we have another class level tear down.

Which is a chance to clean up anything weve left over before the test has a hole.

In order to run our Unit Test, we simply hit Cmd + U. It will open up the simulator for you.

Ill begin writing our tests. You can see them pass in realtime if you have

your pick of the code file open. And youll see at the end that all our tests have succeeded.

If we see a failing test

It will tell us overall that all our tests have failed and it will give us where it is and whatever particular error message we have printed out.

So we determine whether or not the test has failed through various Xcode asserts

And we can see we have a number of different assertions.

Lets say youre brand new to Unit Testing, you dont know any

of these, this is all you have to do, actually the assert. This is just like a standard NSAssert.

Any false value will throw an exception and will have failed the test.

One thing thats incredibly important for at least our unit tests and

arguably all unit tests is the ability to mock objects.

In any of our testing, we try to keepwe only want to be unit testing

the class our tests are built for. Were not doing integration testing, were not

testing how it talks to any other class or even our backend, so we use whats called, ‘mock objects’.

Are most people familiar with that term, mock objects? Very cool.

So, one deficiency that the Xcode testing suite has is it does not include any type of mock library. Theres no ability to create a mock object natively.

There are a number of libraries useful. The one we use in-house is called OCMock. Once again, this is another really

popular library. Youve seen lots of wide previews of this.

There are a coupleId like to touch on just the highlights of mock,

some of the important methods that you would use for this.

So there are two different type of mock objects that you would use. One

is a more traditional live object where it will only expect methods that you have told

it to expect and if it receives anything else it throws an exception and it fails the test.

We have another type called a niceMock and we can, sidenotewe can

mock those classes and protocols. A niceMock of a class or protocol

will simply accept anything you throw at it but not return anything for those values,

it will simply return NIL. So, we also have the method

called Expect on mock objects and the Expect method gives uswe tell this mock object,

hey I am expecting this method to be called when I later call another method’, which

Ill go over next, ‘if you did not receive this message, then you need to throw an exception

an fail the test.’ That the method we call at

the end of our test in order to determine that all expected methods have been called

is called, Verify. Lets say we simply need

to stub a method, there is a handy-dandy method called, Stub. We feed it what method we expect

and we can also give it a return value in order for it to work nicely with anything

else we might be testing. The last thing I wanted to

talk about in terms of Unit Testing is I wanted to touch on Typhoon again, and I wanted to

talk about the TyphoonPatcher class.

If youll give me just one moment

So, the great thing about the Typhoon factory and the assemblies is, we set everything up and we go to runtime

and it works as expected. Lets say Im writing you a test and the class Im unit

testing uses some things from the Typhoon factory but we do not want something from

the production assembly. This is a very common case. We dont want to drag in any other

classes that were not crisscrossing for unit testing in this particular test.

In order to do that, we create our factory with whatever assemblies we need

just as we normally would and then we create an instance of TyphoonPatcher. What TyphoonPatcher

does is that it gives us at runtime the ability to modify what the factory will return.

So you see what weve done here is, for the factory that weve created

here, which includes just the inpoint log assembly. We patch in for the inpoint assembly,

or for the inpoint log assembly factory, forgive me, method, we create a mock in point log

entry factory told to expect and return some things and return that, and in order to give

that information to the factory, we then attach it as a post processor and from that point

forward, that factory will return our mock object that we expect.

Alright, and that I believe is all the code examples I have for unit testing Cocoapods in typhoon. Who wantssure.

Q: So within the unit testing,do you have like, development, QIs and production environment or whats the...

Our unit tests are run onRudy can talk about those next on how unit

tests are run as as part of our continuation integration environment, although we do run

them locally before we commit. Luke >> So the idea of unit tests

is that, thats a suite that Im expecting every developer to execute when they are making

code changes in their local environment but its also part of our continuous integration

environment which will talk about the build pipeline.

So whatever you checked into repository then that is checked out in continuous

integration process and those unit tests are run again.

John >> Certainly.

Audience >> When testing [cant decipher] can you run it outside of a simulator?

John >> This simulator runs every time. It doesnt run on Vice, it does not run outside of anything else. This simulator

will open every time. You dont see anything, the active self doesnt run, its only run in unit tests.

Audience >> [cant decipher]

John >> Keep in mind the Aphen simulator is not an emulator. You wont get the speed

of the device youre using, but no, it wont run from the Mac OS.

One caveat to that, unless youre not doing an iOS app and youre

doing a Cocoa app, an actual Mac application, then theyll run in its native environment.

Audience >> Can you verify that certain values will pass to the given function?

John >> Yes, through mock objects specifically, when we are expecting a particular

method as argument for whatever method were expecting. We can give it either the value

that we expected to get, and if it does not receive that value, the test will fail, or

we can give it an instance of a class called, OCMArg, which you can do some fancy things

with it to determine what it passed in, and you know, ‘does this pass certain variables

or we can just take anything. Whatever passes, we dont really care, just we have to have

something to be able to accept it.

Audience >> What if we need to call the method twice? How do we specify that?

John >> You simply expect it twice and everytime you call and expect on it, its going to add anotherits going to increment

another counter and everytime its called its going to take one off the stack and

then take it off the stack again if weve expected it twice and if it receives another

one, then it fails because it was not expecting it that many times.

Luke >> Cool. That thing we talked about Cocoapods, very important concept. Again,

Cocoapods allows us to manage dependencies you saw a lot of libraries use. OCMock for

example, so you want ot have an ecosystem that is managed through a framework.

How we low these things by pulling framework again allows us to essentially delegate the factory

functionality to a container which then is a byproduct of that allows us to essentially

write unit tests and essentially isolate classes and write very specific test for those classes.

If there are any dependencies between those classes, Typhoon can essentially patch those

classes as OCMock objects. So we essentially can write very expected returns or very expected

results for execution so our tests are very atomic and thats very important. You dont

want to be testing fifty thousand dependencies as one, you want to unit test your one class.

Its very important distinction to make between unit testing and functional testing.

Functional testing allows you to test a lot of different things. Youre focusing on

business logic and you can use automation for that, and thats a different topic,

So let me talk about built process and how it all kind of comes together with a delivery to production and Im going

to start by showing you where we were six months ago, and let me click on that. So

oh thats not cool. Let me do thatand let me do that. Can you guys see that or no? Ok lets do this.

So, this is essentially a diagram of how our release management process looked like. Let me very quickly focus on

couple of key areas here. So if youve done iOS development, you know the concept of provisioning

profiles, certificates. There are various different types of enterprise ad hoc productions

of easy development. So the way this used to work

is that, we actually had our iOS developers maintaining all these certificates through

iTunes Connect and then, they would do their development of the iOS machines and essentiallystop it.

And they would essentially do their local testing by checking out these certificates

that we would export to our Bitbucket repository to do their local essential build which was,

you know we would run Xcode build, it would create Grindr.app, they would then sign it

with the development provisioning profiles and their certificates and then, now we are

able to test our device on the local machine, and they would check in that code into Bitbucket

and then we would our Jenkins process to check that code out and we go through the same process

again where we kind do an Xcode build, we create Grindr.app. We sign it with any of

those. We would have a publishing process that would create these IPAs for enterprise,

Ad Hoc, and when we would use Hockeyapp towere using YouTest for crowd-sourcing our

tests and also our internal QA would then use the Ad Hoc builds to test, right?

Now, where it gets really funny is that now, ok Ive done all my testing,

its great and Im ready to go into production. And then what happens, iOS developers check

out the code to their local box and they go through this build process and on their local

box theyre signing the IPA, I mean, APP with production of provisioning profiles and

then we would upload to iTunes and then eventually it would get to the App store.

Now, when we talk about mature, you know, build management processes, there

a lot of problems here. Number one, developers have access to production and certificates

and provisioning profiling, allowing them to essentially deploy stuff to production.

Thats not what I necessarily want, right? Another thing is, what Im

testing here is really not what Im deploying. There is no release candidate. Because, ok,

Im gonna go through all this effort, and now if my developer foobars their check out,

or if someone between me doing testing, goes in here and checks in some additional code,

then my check out will catch that and in fact, we had a couple of instances where we put

stuff to production that we really didnt want, right?

Amazingly so, this is probably majority of iOS development shops do it that

way, and the reason why is because for whatever reason the tools are not there, the environment

is not mature to automate this process, so we actually spend a lot of time and effort

to build a release management pipeline to do it more like this, which is our new release

process, which is, we have obviously these provisioning profiles, we have release management

function that maintains these. There is a separate Bitbucket repository that governs

these things with separate permissions so developers do not have access to that stuff.

Developers can only do development on their iOS machines. They do this process, they use

the development provision profiles to do unit testing and local testing, but once we get

to the Jenkins box, Jenkins box actually checks out the code, checks out the provisioning

profiles. Thus, through the build process it creates the versioned release candidate

that is then checked into Nexus artifact repository before the signing process so thats my

release candidate. My APP is now a release candidate which I then can draw from and publish

different environments. Once I certify then I use the same artifact from Nexus artifact

repository. Im going to check it out, sign it with production, provisioning profile and

push to an App store and that is being done by my release management not my developers

and thats more in line with the mature enterprise build pipeline release management

process. Quentions. [54:00] Audience >> Do they have to access

into our iTunesaccount or two different [inaudible].

[54:07] Luke >> Essentially developers dont have access toyeahok?

[54:14] Luke >> So thats really what you want. Key here is the release candidate and

actually the usage of the artifact repository. Another thing here, Sonar will talk about

code metrics. Im very big about having empirical data about what my code is like,

you know? Its not a what a cool conversation, I want to see actual metrics, theyre standard

metrics to measure the quality of my code. Well see that in a little bit. And also,

I want to have automated testing as part of the process. So this build, everytime I do

build, right? There is going to be unit testing. Im gonna calculate my metrics. Im gonna

also run my automated fuctional testing, and thats the future were working on that

right now. We are doing a big push to have that done by the end of the summer. At the

end of the day, everytime I do a build, I want to have a couple things get done. I want

to calculate my code quality metrics and I want to fail the build if someone wrote something

without the unit test, which means my code coverage percentage decreased. Also, you know,

if my unit tests fail, obviously I want to fail the build and once on top of that once

the artifact is done, I want to run my automated testing using functional tests, which means

that now Im actually testing the out functionality, right? And that should happen every night,

at least. Right? [55:42] Luke >> So now, developers can innovate,

they can do whatever, they can test different frameworks. Theres a harness in place to

fail fast, preventing me from pushing crap to production.

[55:54] Luke >> So lets talk about how its actually implemented, so Rudy, if you

could take over and talk about our Jenkins setup and the pipeline.

[56:21] Rudy >> Alright, hi guys, so Im now going through some of the stuff that Lukas

and John went through in a little more detail about how the builds are happening, how the

artifacts are stored, how do we track them, and what we do with them after our QA signs

off on them, right? [56:36] Rudy >> So Lukas briefly mentioned,

now what we do is we basically store we build. So Im gonna start with a couple of tools

were actually using in-house. So were using Jenkins for all the build processes.

So we use Jenkins to build the artifacts, we use Sonar, if you guys are familiar with

it, for reporting. So what we do is after we build, we run the Code Quantmetrics and

report it to sonar. So Im gonna put up Sonar and show you guys the dashboard, it

basically tells you where the violations are, what code is missing, unit test coverage,

if they added five classes, and they havent unit tested obviously, the coverage percentage

drops so we can flag it as a failure and ship it back to the dev team before it even makes

it to QA. [57:17] Rudy >> Were using Nexus, its

an artifact group repository. So what we do is, after we have the APP and the IPA artifacts,

we store them there for tracking purposes with the appropriate Git hashes so we can

trace it back to which Git commits they were associated with and we can troubleshoot them

if we need to. [57:35] Rudy >> And Hockeyapp obviously wants

to, if you guys arent familiar with it, to doing distribution of the IPAs.

[57:43] Rudy >> Im gonna start with the iOS sold with the Jenkins piece. So what we

do is we basically use Jenkins to build the artifacts. What we have done is our new build

process basically is thewere tying down a couple moving parts to together to

make this happen so first we start off with Code Quantmetrics. Do they pass? If it does

pass the code quality and were good with that, they have done proper unit testing,

all unit tests pass, they havent broken anything existing. We go ahead and build the

app. Once we build the app, all this stuff is still done in Jenkins. Jenkins will build

the app after doing the reporting to Sonar and store the artifact over at the Nexus repository.

If all that stuff is successful, which means we have a proper IPA, with the right provisional

profile sign, we ship that artifact out to Hockeyapp for QA to be able to download and

take a look at it. [58:41] Rudy >> So here is some of the individual

artifacts we have nest code built. That does the actual build. We have the code quality

metrics that we run right before we run the build. So Im gonna open up one of the jobs

where you can actually see how its tied together. So this is an example of it first,

so first we do the code quality, if its successful we move on with Xcode build and

if that is successful, we move on to storing it in the artifact. We jot that point where

we contact Nexus and we ship out the artifact for storage and retrieval and we sign it with

the proper artifact and we store those. [59:19] Rudy >> The builds themselves take

about five to ten minutes, so with all this stuff included, so from the time that a

go ahead sorry… [59:27] Audience >> When does the get figured?

[59:30] Rudy >> So we have two versions of it, right. We have a calling system which

we keep calling the repository every ten minutes. If there are new commits, we shake it all,

we build it. Automatically. [59:41] Audience >> On any branch?

[59:30] Rudy >> Yeah we have a few active branches that we have job set up for then

we have master and kind of stable branch which is always production-like, plus, the other

option is QA can always trigger it, if they want to. So, those are the options we have

built, and then were also working on refining what the proper incremental timeframe should

be for polling. Is it too frequent or not frequent enough, right? Because if the builds

take about ten minutes you dont want to keep pulling every five minutes. Then you

have your jobs lined up and queued up and its going to bog down Jenkins itself. Any

other questions? [59:41] Audience >> [inaudible]

[59:30] Rudy >> So what we do is, with the code quality metricsso after everything

is done, youll see that the build is successful and this is basically Sonar. So what we do

is we gather all the statistic from unit testing that job went through and we report it to

this tool called Sonarcubes. What it does is that it basically aggregates it and you

see the two green graphs for each branch right now? So, as we keep working on branches and

committing code, the code quality is gone, and reports are getting generated and updated.

If you start missing your commitmentlets say threshold is set up, 90% for unit test

coverage and you add ten new classes and you have no unit test, youre obviously gonna

cut off on that threshold and not meet it. So, were gonna flag it and once we ship

the results here, youre gonna see red and yellow and going all the way down to red obviously.

We can actually enable triggers on these jobs, on this reporting, and say in this case we

have actual coverage set to, if its greater than 65%, mark it as warning. If its greater

than 70%, fail the build. So when the build fails it gets kicked back to the dev team

and theyre like, ‘alright we gotta address this, this is not making it to QA’, because

the next step is actually the build process and that never got triggers, so QA has nothing

to test on. [61:40] Luke >> Let me touch a little bit

on that. So, from the perspective of having metrics on how well youre doing as an engineering

organization, this dashboard is very important to me, because we have multiple teams, we

have multiple, you know, we got Android, we got iOS, we got backend, we got multiple branches.

Setting rules and having these static code analyser rules that the team overtime develops,

is very important, right? Because those are essentially your automated code reviews that

happen every time you build, right? So as youre developing these youre getting

better and better and better, so you can make this a part of your retrospective process

if you want. You can make it more collaborative when developers are updating it all the time.

The bottom line is that those are very important. Another metrics I look at is comment density.

You wanna make sure that your code is well documented. Im not big on writing separate

documents from the code. I think the code in the class is very important, also, thats

on top of naming standards and conventions or whatever. Obviously, if you name your classes

correctly, if you name your method correctly, you dont need comments, but if you dont,

then its a problem. [63:06] Luke >> Duplications, thats very

important for me as well. I dont want copy and paste, right? Its very easy if you

are bending out stuff. Youd be like, okay, that looks cool, Im just going to reuse

it, copy and paste. If that goes up, Im not a very happy person, right? And then,

thats something that we are trying to make work, Cyclomatic complexity is also a very

good metrics to look at anything greater than 5, I usually reject the build, so thats

analogous with having god objects, right? If I have a class with ten thousand lines

and does everything, cyclomatic complexity goes through the roof. I want nice, clean

eco-position, right? So, cyclomatic complexity is one way to ensure that you have that. And

then, our good old unit test coverage, so obviously, we want this number around 80%.

Youre going to have 100% coverage. You may strive for that but I use 80-20 rule.

80% of code coverage is good. The bottom line is that if you set the threshold and if you

setup your failure SLA, youre kind of saying, ok, engineering, we have 60% now. From now

on you cannot decrease this number, you can only go up, which means, now youre forcing

your developers to write code that has proper unit tests in place, and thats part of

your automated process. You dont have to rely on humans to decode reviews of whatever.

Its part of your build pipeline. [64:48] Rudy >> You can kind of have, yeah

go ahead… [64:51] Audience >> Does Sonar sit on top

of your repository as if on github? [64:56] Rudy >> No, this is a separate thing,

this is a separate application. So what it does is, when Jenkins builds it, and it runs

your unit test coverage, it actually publishes the numbers to Sonar. Sonar takes them, figures

out what to do with them and does the whole graphing for you. So its kind of creating

the link between Sonar and Jenkins unit test reporting and it just takes care of everything

else. [65:17] Audience >> So when Jenkins builds

it, it sends it to Sonar? [65:21] Rudy >> Sonar, yeah, It spills the

reports to Sonar. Actually, Im gonna do one thing for the demo right now and then

Ill carry on and you guys can see the difference so Im gonna go to alerts, and you noticed

how to coverage was. I wanted to fail, it gave me a warning at 80% and failed at 90%,

right? [65:52] Rudy >> So Im just gonna trigger

a build right now and we can continue. [66:05] Audience >> So where is it building

from? Is everybody ready with a common file? Is there a server somewhere?

[66:11] Audience >> No, this is checking out the code repository, right, a given branch

and running the unit test coverage and doing the reports. If that is successful and Sonar

doesnt report a failure on that, which means you havent exceeded any of the thresholds,

right, youre still good, and then Jenkins carries on with doing the build, and then

storing the artifact. [66:29] Lukas >> We set up a pipeline, build

pipeline templates through Jenkins, so theres a wizard that we have that allows you to specify

the branch. When you enter the branch, you enter the provisioning profile and that sets

all those builds for you with all those multi-steps building process and then you just schedule

and run. So lets say I have newIve been developing on my feature branches, Ive

been checking through Stable. Im ready to, okay, Ive got enough stuff to do a

release candidate. I would cut the release branch, and then I would go to Jenkins, use

my wizard to set up with this branch build and now our building gets correct. Theres

also a stable branch that well build against all the time. And thats all, you can lock

it. [67:18]Rudy >> So the moving pieces where

getting a build ready for QA is basically checking the code, having proper unit test

coverage. We run the unit test coverage. If everything passes, we run the build, we create

the artifact. If that is successful, we store it over at Nexus and thats the raw APP

file, right? So at that point we can sign it with any provision profile we need which

is an issue that Lukas mentioned that they were having earlier, which is once QA signs

off, the developer checks out the code again and does a brand new build and thats all

gone now. We have the actually raw APP that QA signed off on depending on which provisioning

profile we use. If they sign off on that, we check out the exact APP file. We sign it

with production and we ship that same thing off to Apple.

[68:00] Rudy >> Now, dev could have messed around with the branch as much as they wanted.

That one build is going out, the one QA signed off on, right? Theres no more ifs and buts.

Did we check out the right stuff, did we build it properly. Did you guys update any libraries

locally before building, so… [68:17] Audience >> [inaudible]

[68:25] Lukas >> So there is a difference between unit testing, remember unit testing

isautomation, the functional testing automation, thats a different topic, were going

to have a tech talk on that end of July. [68:40] Audience >> When you are running the

simulator for all your unit testing, do you have running wishes that its of the actual

device like integers? [68:51] Lukas >> So testing of the simulator

is not going to ever be the same like testing on the real device. So again, when youre

setting out the functional automation framework, you want to make sure that youre using

an actual device arm. There are companies that allow you to do that. Or you can have

the fondal devices in-house but youre stuck managing that stuff, again thats an end

of July session. [69:19] Audience >> Thats right, and what

about the iOS expression of iOS7 and they said, you can do iOS7?

[69:24] Lukas >> In the iOS7 youre usually [inaudible]

[69:28] Audience >> Because thats where everybody presents you so much.

[69:32] Lukas >> But we have a QA process we test against different devices.

[69:36] Audience >> Or can be just different versions of it?

[69:40] Rudy >> So thats part of the build deployment process, basically, once all the

builds are ready to go and there are no issues, weso this is Nexus. I dont know how

many of you guys are familiar with Nexus. Its basically a artifact dependency management

system that we put in place. Its open source. You guys can utilize it as well. What we do

is basically after all the artifacts are ready to goIll show you guys this version

actually. [70:13] Rudy >> We store them with the

can you guys see this? Yeah, with the version number and the build number that came through

and if you guys actually expand that, you have multiple versions. You have the Ad Hoc

IPA, you have the Devord IPA and then you have the Tor Bold which is the actual raw

App file. So once QA signs off on this version, lets say, which they did, you check out

the Tor Bold which contains the raw App file. We sign it with production. We store them

here so we know exactly what we released and we ship this one off to the dev, to Apple

Store. So if they have messed up with the branch at any time while QA was testing, 2016-2,

nobody is going to get impacted by it. Well have to do some branch cleap-up later but

the same artifact is gonna make it to production and into the app store. We also stored the

Git hash spirit, so at any point we can track it back and figure out this version was built

based on this Git hash, so we can check it out and figure out what went wrong, if anything,

right? [71:12] Rudy >> So QA will be doingso

once that these are ready and theyre stored on Nexus, we ship them off to Hockeyapp, which

is the application distribution. Portal, basically. The devices connect to it, they download,

they install it, they go off testing. One of the issues we were having was basically

QA could never figure out which build theyre testing because theyre all 2016s, right?

We managed to do custom build numbers so they actually associate with individual Jenkins

builds so we can go back and say, oh ok, so version 5 is actually on Hockeyapp, it can

be downloaded and tested, so when theyre downloading, they actually see the latest

download of the version and they can correlate to know better, the build theyre downloading,

is actually from the last commit or is it from the previous one. Because the upload

to Hockeyapp could have failed, it might have, something might have gone wrong and theyre

just downloading and updating, they might never know. They get to download this stuff,

test it out. Once theyre good with it, well go back to our Jenkins, we have a

process. [72:18] Rudy >> We have a process where we

basically prepare for production and what it does it basically give a version number

and a build number. It checks out the Tor Bold which concerns the App, signs it with

production profile and then uploads it back to Nexus which is available to download so

you can actually click on it. [72:37] Rudy >> Download it and submit it

to the Apple Store. Now this is done between the regions management and the product

owners and we collaborate and figure out when the right time for release is and we just

go do this. So at any time, something that was tested sort of working through at this

point. Any questions, of any of this setup? [72:58] Audience >> Yeah sure, so youve

submitted for certification from Apple because Apple uses all of this still to verify [inaudible]

[73:16] Rudy >> Apple doesnt care about Sonar reporting, yeah, Apple doesnt care

about unit testing, any of that stuff. [73:21] Lukas >> Their evaluation criteria

is based on completely different things, right, versus what we want to do, so, again, tying

it back to what we talked about, you know, we want to enforce engineering standard code

quality. Architectural standards make sure that there is a separation between develop

and release management. There are tools to do that. We talked about Typhoon, Cocoapods,

all that stuff, but it all comes together, right, for you to be able to be comfortable

with experimenting and writing code and being in an environment where we fail fast. We learn

from that, well fix it and then well move on.

[74:06] Audience >> Those people use version dool very differently, in different places,

like [inaudible]. My question is this though, how do you actually, your backend, how do

you make sure that the new feature that you have, that youre putting in there is always

connected to the backend. How do you tie it all together?

[74:29] Lukas >> So youre talking aboutSo our application is powered by Respool APIs

which are versioned. Its a completely different topic, how you manage your Respool APIs. All

I can tell you is that when it comes to like, testing, you know, we have a staging environment,

QA environment since were testing different versions of APIs. There are ways also for

you to set automated testing where you are essentially mocking their responses or mocking

their Jasons. You can use men in the middle or some other proxy where you are replaying

back some things, which kind of goes if you want to have atomic tests. Thats something

that were working on right now. Its part of our automation plan.

[75:14] Audience >> So its not going to be automated before I tend to be line-correct.

[75:17] Lukas >> So we are doing a big push towards functional testing automation. Majority

of our tests are right now in the QA side manual and we use crowd-sourcing through YouTest

to test our application so as far as a road map is concerned, were a big push on the

engineering side to do tester involvement, increase test code coverage, and on the QA

side we also are just starting the automation effort so well be applying some sort of

device farm. Well essentially be able to replace Kreps and simulate user behavior.

[76:01] Audience >> So it sounds like when you started this tester and development, you

had a premature app and there were no [inaudible] so how did you prioritize the coming unit

test build, did you put all of your engineering and development on hold while you, or 50%

or did you write for extra bugs as they came up?

[76:28] Lukas >> Its really a Scrum discussion, right? How do you find that balance between

like building or engineering practice versus your product priorities and all of everything

else? All I can tell you is that were solving for stability and a better build of the app

and you know, when Im having a discussion with my boss or with product, you know, its

kind of a horse trading thing where its like well, you know, we could be cranking

out a lot of features but if were crashing all the time and the app is not stable and

thats not ideal. So you need to find that middle ground, right? The way we solved that

problem is that we said, ok, weve made unit testing part of our definition of done,

which means that if youre building a new feature then you have to write, if youre

attaching an old class, then you have to write a new test for that class. So over time your

test coverage increases, right? [77:34] Audience >> What is the engineering

responsibility? I mean, other than having me having say so, but what is the engineering

response to actually… [77:41] Lukas >> We actually made this decision

collaboratively. It wasnt my mandate. Im not a big fan of just being very heavy handed.

It was a discussion, right? We kind of weighed the pros and cons to different approaches.

At the end of the day, I think, all developers say, yeah its going be kind of sucky to

do this, but we had all gotten bored because at the end of the day we take pride in what

we do so our ship finally flowed. [78:13] Lukas >> Ok, no more questions. Yes,

sir? [78:18] Audience >> [inaudible]

[78:23] Rudy >> Yes, so its a separate topic. We are using Floury, we are using actually

several different libraries. Floury is just part of many. So, again, its kind of goes

with this motto of like, you dont want to be in the business of writing all that

stuff from scratch, right? So if you want to get all this other stuff, you want to integrate

with some sort of a company thats in the business of that so that leaves you free to

do other things, right? But thats a separate topic.

The Description of Grindr Tech Talk: iOS Development with Test Driven Development