Елена Булыгина предлагает Вам запомнить сайт «Ленусик»
Вы хотите запомнить сайт «Ленусик»?
Да Нет
×
Прогноз погоды

Основная статья: Ios

Три свежие книги для начинающих разработчиков Swift

Выбирая книги по разработке на Swift, новичку важно понимать, что это молодой язык, который часто меняется и обновляется. Про Swift написано достаточно много хороших книг, но с выходом новой версии языка они тут же устаревают и вводят в заблуждение неопытных читателей.

Мы подобрали только актуальные книги по Swift, которые вышли недавно либо затрагивают области, не зависящие от версии языка.

Официальная книга Swift Programming Language от Apple

Если с другими более устоявшимися языками разработчики советуют проверенные издания классических IT-авторов, то со Swift вас в первую очередь отправят читать официальную книгу от компании Apple, которая этот язык и разработала.

Swift Programming Language (Swift 4.1 edition) можно бесплатно скачать в itunes. На форумах и личных блогах можно найти переводы российских разработчиков, но они тоже затрагивают только предыдущие версии языка. Если вы читаете на английском, скачивайте последнюю официальную версию книги от Apple. Язык изложения сухой и довольно технический, но есть много примеров кода и даже иллюстрации различных приложений.

О том, с каким языком программирования  вам предстоит работать, можете судить по первой главе книги:

«По традиции, первая программа на новом языке должна выводить на экран словосочетание «Hello, world». На Swift это пишется всего в одну строку:

print("Hello, world!")

Если вы писали до этого код на C или Objective-C, этот синтаксис должен быть вам знаком. На Swift эта строка является законченной программой. Не нужно дополнительно импортировать отдельные библиотеки для таких функций, как ввод/вывод или обработка строк. Код, написанный в глобальной области, используется как входная точка для программы, так что функция main() больше не нужна. Также вам не нужно писать точки с запятой после каждой строки».

Swift для детей

Да, мы предлагаем начинающим разработчикам купить детский учебник. Во-первых, такие книги часто пишут крутые программисты, которые умеют доступно объяснять теорию. А во-вторых, для тех, кто начинает программировать с нуля, важно не испугаться сложных объяснений в начале.

«Swift для детей» — самое свежее издание об этом языке на русском. Для российских читателей издательство «Манн, Иванов и Фербер» выпустило ее в январе 2018 года. Авторы книги — разработчики iOS, многодетная мама Глория Уинквсит и руководитель отдела по созданию приложений для врачей и пациентов Мэтт Маккарти.

Первый раздел посвящен редактору Xcode: как его установить, настроить и написать первый код в XcodePlayground. Cледующие две части — практические. Шаг за шагом авторы издания предлагают написать приложение Birthday Tracker и игру Schoolhouse Skateboarder. В конце учебника — краткий справочник с информацией по официальной документации Swift, комбинациями клавиш для Xcode и симулятора IOS.

Несмотря на красочные детские иллюстрации (а может и благодаря им), книга хорошо подойдет и взрослым. Чтобы оценить, насколько хорошо авторы объясняют материал, посмотрите на отрывок из главы «Как давать названия константам и переменным»:

«Переменную и константу можно называть как угодно, но только не словами, которые используются самим Swift. К примеру, вы не можете называть переменную словом var. Запись var var может привести в замешательство и вас, и компьютер. Если попытаетесь назвать переменную или константу словом, зарезервированным Swift, у вас возникнет ошибка. Также в одном блоке программы «не уживутся» две переменные и константы с одним именем. Не бойтесь использовать длинные названия, избегайте сокращений. Так будет проще разобраться, зачем нужна переменная или константа. Если бы изучали чужую программу, что для вас было бы понятнее — numKids или numberOfKidsInMyClass?».

iOS 11 Programming Fundamentals with Swift: Swift, Xcode, and Cocoa Basics

Автор книги Мэтт Нойбург, судя по его краткой биографии в предисловии, — человек уникальный. С самого детства его одновременно интересовали и литература, и программирование; в обеих сферах он достиг больших успехов. Нойбург защитил докторскую по древнегреческой литературе, написал множество гайдов для программистов и разработал приложения MemoryStick, NotLight и Thucydides. Наверное, поэтому его книги с очень практическим значением такой приятный язык и отличный стиль изложения.

Последняя версия книга вышла в октябре прошлого года и разбирает всю теорию программирования на  Swift 4.0. Информация в издании разбита на 3 большие части:

  • Language (язык)
  • IDE (интегрированная среда разработки)
  • Cocoa (объектно-ориентированный API для macOS)

В предисловии автор довольно нескромно, но очень мотивационно пишет о своей методике обучения Swift:

«Мой способ обучения программированию на Swift отличается от других методик, в том числе от того, что предлагает Apple. Мой подход — систематический, евклидианский, все обучающие блоки связаны между собой и выстроены именно в той последовательности, которую я считаю наиболее эффективной. В то же время, в этом издании я постарался ограничиться основами — не уходить в детали. Swift — язык не сложный, но у него есть свои подводные камни. Я считаю, что не нужно глубоко вникать во все его нюансы сразу, поэтому осознанно не стал объяснять некоторые темы в книге. Например, в этой книге вы не найдете ничего о Swift Playgrounds или REPL. Я сфокусировался на актуальной практике программирования под IOS, поэтому в книге много советов из моего личного опыта разработчика».

Очень жаль, что это издание пока не переведено на русский язык. Но понятный стиль изложения автора поможет вам без особых сложностей изучить издание в оригинале.

Пройти обучение

17 апр 18, 12:33
0 0
Статистика 1
Показы: 1 Охват: 0 Прочтений: 0

Самые распространенные ошибки iOS-разработчиков

Что может быть хуже того момента, когда App Store отвергает ваше приложение из-за багов? Когда приложение с кучей багов размещается в магазине. Оно получает один негативный отзыв, второй… Репутация компании и разработчика катится вниз и восстановить её уже очень сложно.

iOS – вторая по популярности мобильная ОС в мире, причём 65% пользователей использует самую свежую версию. И каждый из них ждёт от любого приложения качества и высокой стабильности. В ситуации, когда к команде разработчиков каждый день присоединяется 1000 новичков, добиться этого не просто. Ниже приведены 10 наиболее популярных ошибок по версии Toptal, которые совершают неопытные iOS-разработчики. Запомните и постарайтесь избегать их.

Отсутствие понимания устройства асинхронных процессов

Одна из наиболее распространённых ошибок – неправильная обработка асинхронного кода. Давайте рассмотрим простой пример: пользователь открывает страницу с таблицей, данные подгружаются с сервера и размещаются в ней. Описать процесс можно так:

@property (nonatomic, strong) NSArray *dataFromServer;
- (void)viewDidLoad {
            __weak __typeof(self) weakSelf = self;
            [[ApiManager shared] latestDataWithCompletionBlock:^(NSArray *newData, NSError *error){
                           weakSelf.dataFromServer = newData;              // 1
            }];
            [self.tableView reloadData];                                  // 2

}

// and other data source delegate methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
            return self.dataFromServer.count;
}

На первый взгляд всё в порядке, но давайте проанализируем: мы сначала получаем данные, потом обновляем UI. Загвоздка в том, что получение данных – асинхронный процесс, и новые данные не будут получены до перегрузки интерфейса. Поэтому данный код необходимо переписать, поставив строку «2» сразу после «1»:

@property (nonatomic, strong) NSArray *dataFromServer;
- (void)viewDidLoad {
            __weak __typeof(self) weakSelf = self;
            [[ApiManager shared] latestDataWithCompletionBlock:^(NSArray *newData, NSError *error){
                           weakSelf.dataFromServer = newData;              // 1
                           [weakSelf.tableView reloadData];       // 2
            }];
}

// and other data source delegate methods

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
            return self.dataFromServer.count;
}

Впрочем, и такая запись может не привести к нужному результату, если…

Запуск кода, связанного с UI, не в главном потоке

Итак, вы переписали код, но наши таблицы всё ещё не заполнены обновлёнными данными. Неужели есть ещё ошибка в столь простом коде? Для поиска ответа остановим код внутри блока и посмотрим, в какой очереди он вызывается. Возможно, он не обновился из-за того, что пользовательский интерфейс обслуживается вне главной очереди.

Многие популярные библиотеки (Alamofire, AFNetworking и Haneke) требуют вызова completionBlock в основной очереди. Но иногда разработчики просто забывают об этом. А ведь сделать это так просто:

dispatch_async(dispatch_get_main_queue(), ^{
  [self.tableView reloadData];
});

Непонимание многопоточности и параллелизма

Параллельную обработку можно сравнить с очень острым ножом: вы можете легко пораниться, если не будете осторожны, но при правильном использовании она придаст коду невероятную эффективность.

Безусловно, в подавляющем большинстве задач вы можете обойтись без параллелизма, но его использование даст следующие преимущества:

  • Почти каждое мобильное приложение использует веб-сервисы (к примеру, для вычислений или работы с БД). Если вы поместите их в главную очередь, то приложение или «подвиснет» на время выполнения, или iOS его закроет, если это затянется надолго.  Именно поэтому перемещение таких операций в параллельный поток – прекрасный выход из ситуации.
  • Все современные iOS-устройства имеют несколько ядер, так почему бы не воспользоваться этим для повышения быстродействия?

Но, как уже было сказано, пользоваться параллелизмом надо уметь. Давайте рассмотрим пару популярных ошибок, связанных с ним (часть кода опущена для удобства):

Случай 1

final class SpinLock {
private var lock = OS_SPINLOCK_INIT

func withLock<Return>(@noescape body: () -> Return) -> Return {
    OSSpinLockLock(&lock)
    defer { OSSpinLockUnlock(&lock) }
    return body()
}
}

class ThreadSafeVar<Value> {
private let lock: ReadWriteLock
private var _value: Value

var value: Value {
    get {
        return lock.withReadLock {
            return _value
        }
    }

    set {
        lock.withWriteLock {
            _value = newValue
        }
    }
}

}

Мультипоточный код:

let counter = ThreadSafeVar<Int>(value: 0)
// this code might be called from several threads
counter.value += 1
if (counter.value == someValue) {
    // do something
}

Итак, мы создали ThreadSafeVar для обработки counter, что должно сделать работу с потоками безопасной. Или нет? Два потока могут достигать линии инкремента одновременно, поэтому выражение counter.value == someValue никогда не станет истиной. Для разрешения этой ситуации создадим ThreadSafeCounter, который возвращает значение после увеличения:

class ThreadSafeCounter {
    private var value: Int32 = 0
    func increment() -> Int {
        return Int(OSAtomicIncrement32(&value))
    }
}

Случай 2

struct SynchronizedDataArray {
    
    private let synchronizationQueue = dispatch_queue_create("queue_name", nil)
    private var _data = [DataType]()
    var data: [DataType] {
        var dataInternal = [DataType]()
        dispatch_sync(self.synchronizationQueue) {
            dataInternal = self._data
        }
        
        return dataInternal
    }
 
    mutating func append(item: DataType) {
        appendItems([item])
    }
    
    mutating func appendItems(items: [DataType]) {
        dispatch_barrier_sync(synchronizationQueue) {
            self._data += items
        }
    }
}

Здесь dispatch_barrier_sync  используется для синхронизации доступа к массиву. К сожалению, код не учитывает, что такой алгоритм будет создавать копию каждый раз при добавлении элемента, что означает добавление очереди к синхронизации.

Да, такой код будет работать. Но потребуется провести несколько тестов, чтобы удостовериться в  том, что потери производительности незначительны. В противном случае стоит искать другое решение.

Незнание тонкостей работы с переменными объектами

Swift очень полезен для предотвращения ошибок с типами, но iOS-разработчики используют также Objective-C. Именно здесь существует опасность с переменными объектами, которые могут приводить к скрытым проблемам. Известно, что неизменяемые объекты должны вызываться из функций, но, к сожалению, немногие знают, почему. Давайте рассмотрим следующий код:

// Box.h
@interface Box: NSObject
@property (nonatomic, readonly, strong) NSArray <Box *> *boxes;
@end
 
// Box.m
@interface Box()
@property (nonatomic, strong) NSMutableArray <Box *> *m_boxes;
- (void)addBox:(Box *)box;
@end
 
@implementation Box
- (instancetype)init {
    self = [super init];
    if (self) {
        _m_boxes = [NSMutableArray array];
    }
    return self;
}
- (void)addBox:(Box *)box {
    [self.m_boxes addObject:box];
}
- (NSArray *)boxes {
    return self.m_boxes;
}
@end

Код корректен, NSArray является подклассом NSMutableArray. Так что может пойти не так?

Чаще всего проблема возникает, когда другой разработчик решает сделать следующее:

NSArray<Box *> *childBoxes = [box boxes];
if ([childBoxes isKindOfClass:[NSMutableArray class]]) {
                // add more boxes to childBoxes
}

Это действие крайне негативно скажется на работе класса.

А вот другой случай, в результате которого программа поведёт себя непредсказуемо:

Box *box = [[Box alloc] init];
NSArray<Box *> *childBoxes = [box boxes];
 
[box addBox:[[Box alloc] init]];
NSArray<Box *> *newChildBoxes = [box boxes];

Вы ожидаете, что [newChildBoxes count] > [childBoxes count], но что если не так? В этом случае класс плохо описан, так как он меняет значение, которое уже возвращено.

Исправить это можно, если вы допишете в начальный код:

- (NSArray *)boxes {
    return [self.m_boxes copy];
}

Непонимание принципов работы NSDictionary

Если вы когда-нибудь работали с NSDictionary и произвольным классом, то знаете, что не можете использовать класс, если он не соответствует NSCopying в качестве ключа словаря. Многие iOS-разработчики задаются вопросом, зачем Apple добавила это ограничение.

Вам поможет понимание работы  NSDictionary. Технически это всего лишь хэш-таблица. Упрощённо рассмотрим, как она работает при добавлении объекта в качестве ключа:

  • Шаг 1: рассчитывается hash(Key).
  • Шаг 2: основываясь на хэше, ищется место для размещения объекта. Обычно это делается путем вычисления модуля хэш-значения со значением словаря. Затем полученный индекс используется для хранения пары «ключ / значение».
  • Шаг 3: если в этом месте отсутствует объект, то создаётся связанный список для записи и хранения нашей пары «ключ/значение». В противном случае пара добавляется в конец списка.

А вот как извлекается:

  • Шаг 1: высчитывается hash(Key).
  • Шаги2: ищется ключ по хэшу. Если данные отсутствует, возвращается nil.
  • Шаг 3: если там связанный список, выполняются итерации объекта, пока [stored_key isEqual:Key].

На основании этого мы можем сделать два вывода:

  • Если хэш ключа изменяется, запись должна быть перенесена в другой связанный список.
  • Ключи должны быть уникальными.

Давайте рассмотрим это на простом классе:

@interface Person
@property NSMutableString *name;
@end
 
@implementation Person
 
- (BOOL)isEqual:(id)object {
  if (self == object) {
    return YES;
  }
 
  if (![object isKindOfClass:[Person class]]) {
    return NO;
  }
 
  return [self.name isEqualToSting:((Person *)object).name];
}
 
- (NSUInteger)hash {
  return [self.name hash];
}
 
@end

Теперь представьте, что NSDictionary не копирует ключи:

 
NSMutableDictionary *gotCharactersRating = [[NSMutableDictionary alloc] init];
Person *p = [[Person alloc] init];
p.name = @"Job Snow";
 
gotCharactersRating[p] = @10;

Потом мы обнаруживаем опечатку и исправляем её:

p.name = @"Jon Snow";

Что происходит со словарём? Поскольку имя изменено, изменился и хеш. Теперь наш объект находится в неправильном месте, так как всё ещё имеет старое значение хэша, а словарь не знает об изменении. Таким образом, не ясно, какой хэш мы должны использовать для поиска данных в словаре.

Или ещё хуже. Представьте себе, что мы уже имели «Jon Snow» в нашем словаре с рейтингом 5. Словарь будет иметь два разных значения для одного и того же ключа.

Как видите, невнимательность может создать много проблем при работе с изменяемыми ключами NSDictionary. Лучшим выходом будет копирование объектов перед сохранением с соответствующей пометкой.

Использование StoryBoard вместо XIB

Большинство новых разработчиков iOS следуют рекомендациям Apple и используют сториборды по умолчанию для UI. У такого подхода есть не только [спорные] преимущества, но и явные недостатки. Начнём с плохого:

  • Использование Storyboard несколькими членами команды – крайне сложная задача. Технически реально использовать несколько сторибордов, но для этого придётся прописывать переходы.
  • Имена переходов и контроллеров в сторибордах – строки, которые вам придётся прописывать в коде (а из-за их количества это его уничтожит). Или создавать огромный список констант. Можно ещё использовать SBConstants, но это тоже не сильно упрощает задачу.
  • Использование сторибордов практически исключает модульное программирование из-за малого числа повторов. Для минимального продукта (MVC) или прототипа это не критично, но для настоящего приложения это очень важный недостаток.

Преимущества:

  • Навигация интуитивно понятна. Теоретически. Фактически реальное приложение имеет десятки контроллеров, подключённых в разных направлениях. То есть навигация будет выглядеть как большой клубок ниток, который точно не даст вам понимания о взаимодействии данных.
  • Статические таблицы. Это неоспоримое преимущество, если не считать того, что 90% всех статических таблиц рано или поздно становится динамическими. А в этом случае лучше работать с XIB.

Путаницы со сравнением указателей и объектов

При сравнении двух объектов мы можем использовать два подхода: сопоставление указателей и самих объектов.

Равенство указателей означает, что оба ссылаются на один и тот же объект. В Objective-C мы используем для этого ==. Равенство объектов означает, что оба логически идентичны. К примеру, как один и тот же пользователь из разных таблиц. В Objective-C для этого используется isEqual или, что даже лучше, isEqualToString, isEqualToDate и т.д.

Взгляните на следующий код:

NSString *a = @"a";                      // 1
NSString *b = @"a";                         // 2
if (a == b) {                               // 3
    NSLog(@"%@ is equal to %@", a, b);
} else {
    NSLog(@"%@ is NOT equal to %@", a, b);
}

Что появится в  консоли, когда мы запустим код? Мы увидим «a is equal to b», так как оба указателя ссылаются на один и тот же объект в памяти.

Но теперь давайте изменим строку # 2 на:

NSString *b = [[@"a" mutableCopy] copy];

И теперь мы увидим «a is NOT equal to b» потому что указатели ссылаются на разные объекты, хоть визуально они и идентичны.

Проблема решает использованием isEqual или типизированной функцией. Внесём изменение в строку «3» и запишем код правильно:

if ([a isEqual:b]) {

Использование строго заданных значений

Существуют две основные проблемы со строго заданными значениями:

  • Часто неясно, что они представляют.
  • Если они используются в нескольких местах в коде, они должны быть повторно введены (или скопированы и вставлены).

Взгляните на пример:

if ([[NSDate date] timeIntervalSinceDate:self.lastAppLaunch] < 172800) {
    // do something
}
or
    [self.tableView registerNib:nib forCellReuseIdentifier:@"SimpleCell"];
    ...
    [self.tableView dequeueReusableCellWithIdentifier:@"SimpleCell"];

Что такое 172800 и почему именно это значение? На самом деле это число секунд в 2 сутках (то есть 24*60*60*2).

Вместо подобной записи вы можете определить значение с помощью инструкции #define. Например:

#define SECONDS_PER_DAY 86400
#define SIMPLE_CELL_IDENTIFIER @"SimpleCell"

#define – это макрос препроцессора, который заменяет значение именем в коде. То есть, если вы пропишите #define в файле заголовка и импортируете его где-нибудь, все вхождения будут заменены на строго заданные значения.

Но это решение не работает, когда возникает путаница с типами. Для его иллюстрации взгляните на код:

#define X = 3
...
CGFloat y = X / 2; 

Наверняка вы ждёте, что значение y будет 1.5, но это не так. На самом деле оно примет значение 1. Причина в том, что #define не имеет информации о типе. Так что в нашем случае на основании двух значений типа Int (3 и 2) получается результат также типа Int вместо Float.

Этого можно избежать, используя константы:

static const CGFloat X = 3;
...
CGFloat y = X / 2;  // y теперь 1.5

Использование default в конструкции switch

Использование выражения default в конструкции switch может привести к ошибкам и неправильной работе. Взгляните на код, написанный на Objective-C:

typedef NS_ENUM(NSUInteger, UserType) {
    UserTypeAdmin,
    UserTypeRegular
};
 
- (BOOL)canEditUserWithType:(UserType)userType {
    
    switch (userType) {
        case UserTypeAdmin:
            return YES;
        default:
            return NO;
    }
    
}

Аналогичный код на Swift:

enum UserType { case Admin, Regular } func canEditUserWithType(type: UserType) -> Bool { switch(type) { case .Admin: return true default: return false } }

Данный код описывает алгоритм, позволяющий вносить изменения только администраторам. Но что произойдёт, если мы захотим открыть доступ ещё и менеджерам? Ничего не получится, если мы не обновим блок кода switch. Однако если вместо default использовать значения enum, изменения будут учтены при компиляции и вы сможете это исправить перед тестированием или выпуском приложения. Вот так это должно выглядеть на Objective-C:

typedef NS_ENUM(NSUInteger, UserType) {
    UserTypeAdmin,
    UserTypeRegular,
    UserTypeManager
};
 
- (BOOL)canEditUserWithType:(UserType)userType {
    
    switch (userType) {
        case UserTypeAdmin:
        case UserTypeManager:
            return YES;
        case UserTypeRegular:
            return NO;
    }
    
}

Так – на Swift:

enum UserType {
    case Admin, Regular, Manager
}
 
func canEditUserWithType(type: UserType) -> Bool {
    switch(type) {
        case .Manager: fallthrough
        case .Admin: return true
        case .Regular: return false
    }
}

Использование NSLog для журнала логов

Многие iOS-разработчики используют NSLog в своих приложениях, чтобы вести служебные записи, однако это может стать большой ошибкой. Взгляните на документацию Apple, а именно на описание функции NSLog. Всё очень просто:

void NSLog(NSString *format, ...);

Проблема в том,что, если вы подключите своё устройство к XCode Organizer, увидите все свои отладочные сообщения. Именно по этой причине не стоит использовать NSLog для журнала: он содержит много нежелательной информации, кроме того, это выглядит непрофессионально.

Поэтому лучше заменить NSLogs на настраиваемый CocoaLumberjack или какой-нибудь фрейморк для протоколирования.

iOS — очень мощная и быстро развивающаяся платформа. Apple прилагает огромные усилия, чтобы внедрить новое оборудование и функции для самой iOS, а также постоянно расширять язык Swift.

Знание Objective-C и Swift сделает вас отличным разработчиком iOS и предоставит возможности для работы над сложными проектами с использованием передовых технологий.

Пройти обучение

3 апр 18, 18:09
0 0
Статистика 1
Показы: 1 Охват: 0 Прочтений: 0

Мобильные приложения: как оценить основную идею

Поведение пользователей изменилось. Несколько лет назад они практически ежедневно заходили в AppStore или GooglePlay, чтобы найти интересное мобильное приложение, а потом им поделиться. Сегодня мобильные приложения выполняют в основном утилитарную функцию. Они должны упрощать жизнь, делать доступ к услуге удобнее и быстрее. Память в смартфоне ограничена, поэтому количество установленных приложений тоже сокращают, оставляя необходимые. Приложения с размытой идеей и неясной концепцией не смогут выжить на рынке. При создании приложения лучше сразу отталкиваться от требований пользователей и отвечать их ожиданиям.

Выбираем идею

Востребованное мобильное приложение соответствует трем принципам: people, tech, business.

Принцип People — приложение должно вызывать желание им пользоваться.

Принцип Tech — приложение должно быть реализуемо технически. Зачастую хорошие бизнес-идеи не имеют подробной схемы реализации, поэтому во время разработки может оказаться, что еще нет технологий для воплощения идеи в жизнь.

Громкий проект «шлем виртуальной реальности для программистов» потерпел фиаско. На первый взгляд идея — бомба. Программист надевает шлем и погружается внутрь кода. Его ничто не отвлекает, он полностью сосредоточен. Но на практике оказалось, что картинка получается недостаточно четкой для написания кода. Текст выглядит размытым.

Вторым недостатком стала задержка между временем введения символов и моментом, когда их видит программист. Задержка составляет несколько секунд, но этого достаточно, чтобы у большинства испытуемых закружилась голова. На практике получилось, что хорошая идея не может быть реализована технически.

Принцип Business — приложение должно выполнять бизнес-задачи. Каждое мобильное приложение — отдельный бизнес-проект. Не проработанное до конца приложение не станет востребованным. Пользователи придут благодаря агрессивной рекламной кампании, но скоро разочаруются в приложении, которое лагает или не соответствует ожиданиям, и удалят его. Инвесторы обращают внимание не только на количество скачиваний, но и на показатель Uninstall Rate, который информирует о соотношении количества деинсталлированных приложений к количеству установленных за определенный промежуток времени.

Приложение должно решать четыре задачи:

  • Преследовать цели бизнеса.
  • Решать проблемы бизнеса: оптимизировать, упрощать, делать удобнее.
  • Решать проблемы пользователя.
  • Создавать дополнительную ценность для пользователя.

На рынке существует большое количество агрегаторов авиабилетов, но SkyScanner дал пользователям большее, чем просто поиск. У приложения есть поиск аэропорта по странам. Нужно ввести только название страны, чтобы увидеть города, где есть аэропорты, и стоимость билетов до них. SkyScanner упрощает жизнь потребителя и дает дополнительные возможности, т. е. создает дополнительную ценность.

Отбираем функционал

Количество дополнительного функционала может быть ограничено только фантазией и финансированием создателей. Однако не все задуманные функции нужно реализовывать. Некоторые будут слишком затратны в разработке, другие — не востребованы пользователями. Чтобы создать только необходимый функционал, следует провести исследования.

«Ценность против рисков». Матрица используется для отбора функций для разработки и расставления приоритетов очередности. Необходимо каждую функцию оценить по типам риска:

  • просрочить дедлайн;
  • превысить финансирование;
  • не справиться с разработкой.

Также каждой функции присваиваем ценность. В итоге получаем наглядную карту, какие функции реализовывать и в какую очередь. Чем выше польза и ниже риск, тем быстрее необходимо разработать функционал.

Buy a feature. Методика основана на принципе геймификации. Проводится среди потенциальных пользователей мобильного приложения. Все функции необходимо оценить по трем критериям:

  • время разработки;
  • сложность реализации;
  • необходимые ресурсы.

Затем для каждой функции назначаем цену. Всем участникам выдаем определенное количество денег в размере от ⅓ до ½ стоимости всех функций и предлагаем купить нужную. Поведение пользователей покажет, какой функционал важен и насколько.

Модель Кано. Модель была разработана японским ученым Нориаки Кано и основывается на степени удовлетворенности потребителей. Модель универсальна и может применяться ко всем видам товаров и услуг. Основной посыл: продукт должен не только удовлетворять ожидания, но и предвосхищать их. Для создания модели проводят опрос целевой аудитории. Оценивать можно и нужно как проектируемый продукт, так и действующее приложение. Пользователям предлагается оценить каждую функцию приложения в соответствии со шкалой ожиданий.

I like it — I expect it — I am neutral — I dislike it but can accept it — I dislike it and can not accept it 

На основании ответов строится диаграмма, где:

  • attractive — то, что пользователи не ожидают увидеть и чем они восхищаются и готовы поделиться;
  • performance — то, что является конкурентным преимуществом;
  • must-be — то, что ожидают увидеть в приложении;
  • indifferent — то, что не вызывает эмоций у пользователей.

Оси координат обозначают: ось Х — функционал, ось Y — удовлетворенность.

Также каждой функции пользователи присваивают приоритет от 1 до 9 баллов, где 1 - совсем не важно, 9 - очень важно. Кроме этого, каждый вариант ответа имеет свой показатель в баллах:

  • I like it — 4;
  • I expect it — 2;
  • I am neutral — 0;
  • I dislike it but can accept it — (-1);
  • I dislike it and can not accept it — (-2).

Подсчитываем ответы и получаем точки в системе координат, по которым строится модель.

Оцениваем стоимость

Широта функционала мобильного приложения напрямую влияет на стоимость его разработки. Для предварительной оценки создателям нужно знать две переменные: количество часов, необходимых для разработки конкретного функционала, и стоимость часа разработки. Таким образом, получим предварительную стоимость каждого реализованного решения. Сумма решений будет общими затратами на разработку приложения.

Существуют специальные интернет-проекты, которые позволяют выяснить ориентировочную стоимость разработки приложения. Они работают как калькуляторы: отвечаете на вопросы, получаете цену разработки. Популярные проекты:

Разработка MVP (minimum viable product) занимает примерно от двух недель до четырех месяцев. По оценке портала AppTractor, стоимость разработки MVP в 2017 г. составляет 150-250 тысяч руб. на одну платформу или 350-450 тысяч руб. на обе платформы и серверную часть.

По данным компании Aspirity, стоимость разработки мобильных и веб-продуктов зависит от типа подрядчиков. Самый экономный вариант — договор напрямую с программистом и оплата в «черную».

Разработчик

Цена за час, руб.

Лендинг

(50 ч)

MVP (150 ч)

Мобильное приложение на 1 платформу  (300 ч)

Программист, оплата в конверте

550

27 500

82 500

165 000

Программист, оплата через ИП

600

30 000

90 000

180 000

Фрилансер

850

42 500

127 500

255 000

Программист в штате

850

42 500

127 500

255 000

Веб-студия

1300

65 000

195 000

390 000

Тестируем гипотезу

Каждая придуманная идея — гипотеза, которая должна быть подтверждена или опровергнута. Существует ряд методик и тестов. Самый элементарный — «коридорный тест». Основатели рисуют на бумаге макет будущего приложения и выходят с опросом «в коридор», т. е. опрашивают друзей и знакомых, насколько им нравится идея и будут ли они пользоваться таким продуктом. На коридорной стадии отсеиваются самые нежизнеспособные варианты.

Другие способы тестирования предполагают наличие MVP — минимально жизнеспособного продукта. Его создание не должно занимать много времени, но реализация должна включать главные функции приложения. Две основные задачи стоят перед MVP. Первая - дать возможность потребителю оценить продукт. Вторая - собрать информацию для подтверждения или опровержения гипотезы.

MVP для предзаказа. Основная идея тестирования — найти потенциальных покупателей или инвесторов. Создатели могут сделать прототип проекта или разработать сайт, чтобы рассказать о приложении, показать, для чего оно будет создано и какие проблемы решит. После этого попытаться найти желающих купить будущий продукт. Это может быть соглашение о намерениях или предзаказы на краудфандинговых платформах Kickstarter или Planeta.ru. В любом случае создатели ждут от потенциальных покупателей денежных обязательств, а не просто контактных данных в виде имени и телефона.

Комьюнити MVP. Сначала формируется база лояльных потребителей, затем создается приложение для них. База бывает в виде базы рассылок, аудитории блога, сайта, группы в соцсетях, профессионального сообщества. Существующее коммьюнити позволяет анализировать поведение и потребности клиентов, создавать решения конкретно под их нужды и продвигать приложение.

MVP «Волшебник страны Оз». В этом варианте создатели вручную делают то, что программа должна делать автоматически. На одной стороне — потребитель, который использует приложение в соответствии с заявленным функционалом, а на другой стороне — разработчики, которые вручную выполняют заявленный функционал, потому что приложение еще не готово. Они создают «волшебство» для пользователя вручную. Такое тестирование позволяет собрать информацию о поведении целевой аудитории и о готовности клиентов платить. Применяют этот тип тестирования в следующих случаях:

  • чтобы не создавать заранее сложные алгоритмы;
  • чтобы оценить работу приложения для двусторонних рынков;
  • чтобы соблюсти законодательство при работе приложения в деликатных сферах: здравоохранение, знакомства, финансы и пр.

MVP «Консьерж». Тестирование похоже на «Волшебника страны Оз», но в этом варианте пользователь знает, что с ним работают лично и индивидуально. Здесь разработчики выступают в роли высококвалифицированного консьержа, готового выполнить запросы клиента. «Консьерж» применяют, когда успех приложения зависит от каждого пользователя (например, приложение для работы внутри компании), или основные потребители находятся оффлайн, или невозможно заранее оценить операционные расходы и логистику выполнения услуги. Тестирование позволяет собрать информацию о целевой аудитории и оценить возможности монетизации.

Одновариантный MVP. Созданное приложение выполняет только одну функцию. Приложения для заказа такси может только заказать такси. В нем нет дополнительных услуг и бонусов. Одновариантный MVP дает пользователю одну услугу, но выполняемую максимально хорошо. Такой вариант позволяет быстрее выйти на рынок и завоевать свою долю на нем. При хороших показателях скачиваемости и монетизации приложение дорабатывают дальше и дополняют фишками и бонусами. Какой именно функционал следует добавить, узнают из жалоб существующих клиентов. Если жалоб нет, это плохой знак. Значит, для клиентов приложение не имеет ценности.

Заключение

По данным AppAnnie, количество новых приложений растет в геометрической прогрессии. За октябрь 2017 г. в Google Play было добавлено 150 тысяч новых приложений, в App Store — 50 тысяч. Всего на конец октября 2017 г. суммарное количество мобильных приложений в Google Play и App Store составляет 5,5 млн. В таких условиях добиться успеха новому приложению не просто. Чтобы создать востребованный продукт:

  1. Выбирайте идею, опираясь на принципы people, tech, business.  
  2. Проводите исследования целевой аудитории до разработки.
  3. Включайте в приложение только востребованный функционал.
  4. Тестируйте гипотезу с помощью MVP.
Пройти обучение

29 мар 18, 19:23
0 0
Статистика 1
Показы: 1 Охват: 0 Прочтений: 0
Темы с 11 по 13 | всего: 13

Последние комментарии

нет комментариев
Читать

Поиск по блогу

Люди

7 пользователям нравится сайт lena2018.mirtesen.ru