Pull to refresh
17
0
Данил Никифоров@danilNik

Remote CTO

Send message
Спасибо за практические приемы! Теперь главное не забыть про все эти волшебные фразы когда окажешься в подобных ситуациях. Захотелось поучаствовать в тренинге, потому что понимаю что для закрепления подобной информации нужно, как собаке Павлова, пережить позитивный опыт. Почувствовал это сам на тренингах по психологическому консультированию и по win-win переговорам.
А можно ссылки на картинки поправить? Все куда-то исчезли…
Спасибо за подробный материал!

«Блоки могут создавать циклы владения.»
Ну может все-таки оставить название retain cycle? Оно в принципе принято среди iOS разработчиков.
«В следующей статье могу описать, как создать свой WhatsApp при помощи открытых инструментов за 4-5 часов работы. Конечно, если вам, дорогие читатели, будет интересно.»

Не думаю что за 4-5 часов работы можно сделать что-то уникальное. Вы случаем на PubNub имеете ввиду под «открытыми инструментами»? Так там все достаточно просто, советую не портить карму.
либо написать программу, которая докажет обратное.
ну окончательно ответа, на сколько я понял, нет, постоянно появляются новые публикации на эту тему. я думаю это скорее вопрос классификации.

«Однако у некоторых растений возможны гораздо более быстрые движения, например у мимозы, венериной мухоловки и др. Все основные движения растений обусловлены главным образом изменением тургорного давления в клетках.» то есть нервных клеток у них вроде как нет
evolution.powernet.ru/history/ev_nervoussystem.html
Наилучший критерий для определения того кого есть «этично», а кого нет — это наличие нервной системы. Почти у всех растений нету нервной системы и они не могут испытывать боль.
Сначала подумал, что имеется в виду, что есть спрос на разработчиков фреймворков.
Фреймворки это ведь только инструмент, главное чтобы человек кодил нормально: использовал SOLID подход и паттерны применял умно.
«Программирование — это единственная область, где с костылями быстрее, чем без них» Максим Дорофеев
Поэтому я обожаю такую фичу Xcode:

image

Сразу понятно кто что написал и почему
а я в итоге устроился туда, где мне понравилось как меня «отсобеседовали». Процесс длился два часа и я понял что для меня тут большое поле для роста
Вернее Pointer понятно как создаются. Но есть такой кейс: если ты в одном месте(по ошибке) присваиваешь полю не тот тип, а поля еще нет, то тогда оно создастся с этим типом и потом, когда вызовется код, который проставляет в это поле значение с правильным типом, появится ошибка.
Да, вроде это тоже работает, но полной уверенности в том что вся модель простроиться нету. Например не совсем понятно как будут создаваться Pointer на объекты. Пару раз мы давали тестерам протестировать работу приложения с не обновленной моделью базы для, специально чтобы проверить как работает автосоздание полей, вроде все ок, но при обновлении продакшен БД на такие эксперементы я бы не пошел.
А async.js удобно использовать, когда тебе надо параллельно несколько функций запустить, например, когда у тебя запуск cloud code не укладывается в timeout.

Да, тут надо всю информацию по разработке на Parse в отдельную статью оформлять. Я еще могу поделиться тем, как писал код для подсчета статистики — там я столкнулся и c timeout и с burst limit. А еще с тем, что на parse не работают setTimeout() и sortBy()
Ну я предполагал, что можно красивое решение найти, жаль что мы тут поспешили. Спасибо за очень полезную информацию!

А можешь поподробнее описать как ты environment для тестов поднял?
«Я просто размещаю тесты в каталоге public и открываю как обычные веб страницы» то есть папка public лежит в cloud на parse? А как там код можно запускать не через API, а в браузере?
На cloud code основная сложность в том, чтобы вызвать финальный callback только после выполнения всех необходимых операций. Все операции идут асинхронно. Самый простое решение, расположить вызовы функций таким образом:
image
И в конечном callback, самой последней функции, мы просто вызываем наш финальный callback, который возвращает ответ клиенту.
Поначалу я забивал на этот ужас, а потом заинтересовался как же все-таки можно хотя бы(!) уменьшить ширину кода, есть ли какой-нибудь syntactic sugar. Сначала, я начал везде пользоваться promises — они делают код чуть чуть читабельнее, все-таки это не было панацеей и тогда я нашел async.js, которая позволяет получать финальный callback, после завершения сколь угодно большого количества функций выполняющихся параллельно, последовательно, в цикле с разными параметрами и т.д.

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

функция очень большая, и читать не удобно.
exports.deletePictureFromUserProfile = function(deletingPictureId, customCallBack) {
	var arrayForDelete = [];
	picturesQuery = new Parse.Query("Picture");
	picturesQuery.equalTo("objectId", deletingPictureId);
	var query = new Parse.Query("LockSlot");
	query.matchesQuery("picture", picturesQuery);	
	query.find().then(function(results){
		if(results){
 		   for(var i=0,l=results.length; i < l ; i++){
			   	results[i].unset("picture");
 				results[i].save(null,{
 					success: function(myObject) {
 						return [];
 					},
 					error: function(myObject, error) {
 						console.error(error);
 						return [];
 					}
 				});
 			}
		}else{
			return [];
		}
	}).then(function(results){
		var query = new Parse.Query("xxxxx");
		query.matchesQuery("onePicture", picturesQuery);
		query.find().then(function(results){
			arrayForDelete.push.apply(arrayForDelete,results);
			return arrayForDelete;
		}).then(function(results){
			var query = new Parse.Query("xxxx");
			query.matchesQuery("onePicture", picturesQuery);
			query.find().then(function(results){
				arrayForDelete.push.apply(arrayForDelete,results);
				return arrayForDelete;
			}).then(function(results){
				var query = new Parse.Query("xxxx");
				query.matchesQuery("pictureFrom", picturesQuery);
				query.find().then(function(results){
					arrayForDelete.push.apply(arrayForDelete,results);
					return arrayForDelete;
				}).then(function(results){
					var query = new Parse.Query("xxxxx");
					query.matchesQuery("pictureTo", picturesQuery);	
					query.find().then(function(results){
						arrayForDelete.push.apply(arrayForDelete,results);
						return arrayForDelete;					
					}).then(function(results){

						var query = new Parse.Query("xxxxx");
						query.matchesQuery("picture", picturesQuery);
						query.find().then(function(results){
							arrayForDelete.push.apply(arrayForDelete,results);
							return arrayForDelete;												
						}).then(function(results){
							var query = new Parse.Query("xxxxx");
							query.matchesQuery("picture", picturesQuery);
							query.find().then(function(results){
								customCallBack();
							}).then(function(results){
								var query = new Parse.Query("Picture");
								query.equalTo("objectId", deletingPictureId);
								query.first().then(function(image){
									arrayForDelete.push(image);
									if(arrayForDelete){
										console.log("we got arrray for delete");
										var num_of_deleted_objects = 0;
										for(var i=0,l=arrayForDelete.length; i < l ; i++){
											var object = arrayForDelete[i];
											if(object){
												object.destroy().then(function(results){
													num_of_deleted_objects++;
													if(num_of_deleted_objects==l){
														customCallBack();
													}
												});
											}
										}
									}
								}, function(error) {
									console.error(error);
									customCallBack();
								});
							}, function(error) {
								console.error(error);
								customCallBack();
							});
						}, function(error) {
							console.error(error);
							customCallBack();
						});
					}, function(error) {
						console.error(error);
						customCallBack();
					});
				}, function(error) {
					console.error(error);
					customCallBack();
				});
			}, function(error) {
				console.error(error);
				customCallBack();
			});	
		}, function(error) {
			console.error(error);
			customCallBack();
		});
	}, function(error) {
		console.error(error);
		customCallBack();
	});
}


А с async.parallel так:
функция очень большая, но читать удобнее
function deletePictureObjFromUserProfile(picture, customCallBack){
	var resultArrayForDelete = [];
	resultArrayForDelete.push(picture);
	async.parallel([
		function(callback){
			var query = new Parse.Query("xxxx");
			query.equalTo("pict", picture);	
			query.find().then(function(results){
				
				if(results.length>0){
					var currentOperation =0;
					var numOfOperation = results.length;
					function enumCallBack(){
						currentOperation++;
						if(currentOperation==numOfOperation)
							callback();
					};
		 		   for(var i=0,l=results.length; i < l ; i++){
					   	results[i].unset("pict");
		 				results[i].save(null,{
		 					success: function(myObject) {
		 						enumCallBack();
		 					},
		 					error: function(myObject, error) {
		 						console.error(error);
		 						enumCallBack();
		 					}
		 				});
		 			}
				}else{
					callback();
				}
			},
			function(error){
				console.error(error);
				callback();
			});
		},
		function(callback){
			var query = new Parse.Query("xxxxx");
			query.equalTo("onePict", picture);	
			query.find().then(function(results){
				resultArrayForDelete.push.apply(resultArrayForDelete, results);
				callback();
			},
			function(error){
				console.error(error);
				callback();
			});
		},function(callback){
			var query = new Parse.Query("xxxxx");
			query.equalTo("anotherPict", picture);	
			query.find().then(function(results){
				resultArrayForDelete.push.apply(resultArrayForDelete, results);
				callback();
			},
			function(error){
				console.error(error);
				callback();
			});
		},function(callback){
			var query = new Parse.Query("xxxxxx");
			query.equalTo("pictFrom", picture);	
			query.find().then(function(results){
				resultArrayForDelete.push.apply(resultArrayForDelete, results);
				callback();
			},
			function(error){
				console.error(error);
				callback();
			});
		},function(callback){
			var query = new Parse.Query("xxxxxxx");
			query.equalTo("pictTo", picture);	
			query.find().then(function(results){
				resultArrayForDelete.push.apply(resultArrayForDelete,results);
				callback();
			},
			function(error){
				console.error(error);
				callback();
			});
		},function(callback){
			var query = new Parse.Query("xxxxxxxxxxx");
			query.equalTo("pict", picture);	
			query.find().then(function(results){
				resultArrayForDelete.push.apply(resultArrayForDelete, results);
				callback();
			},
			function(error){
				console.error(error);
				callback();
			});
		},function(callback){
			var query = new Parse.Query("xxxxxxx");
			query.equalTo("pict", picture);
			query.find().then(function(results){
				resultArrayForDelete.push.apply(resultArrayForDelete,results);
			},
			function(error){
				console.error(error);
				callback();
			});
		}
	],
	function(error, results){
		if(error)
			console.error(error);
		if(resultArrayForDelete.length>0){
			Parse.Object.destroyAll(resultArrayForDelete, function(success, error) {
				if(error)
					console.error(error);
				customCallBack();
			},
			function(error){
				customCallBack();
			});
		}else{
			customCallBack();
		}
		
	});
}
Для использования XMPP нужен сервер. Клиент не хотел сервера ни в каком виде. Даже для шедулинга и запуска некоторых скриптов на Parse мы использовали беслатный сервис iron.io, только потому что клиент настаивал на server less решении.
Я не хочу устраивать очередной холивар на эту тему, потому что ее уже разобрали по косточкам. Например тут: www.raywenderlich.com/51992/storyboards-vs-nibs-vs-code-the-great-debate
(см. комментарии)
В этом проекте все было реализовано на ксибах. А вообще я не против использования сторибордов.
если человек не знает что ответить, то достаточно посмотреть на то как он рассуждает, для этого и нужны каверзные вопросы

Information

Rating
Does not participate
Location
Екатеринбург, Свердловская обл., Россия
Date of birth
Registered
Activity

Specialization

Фулстек разработчик, Технический директор
Ведущий
From 600,000 ₽
Управление проектами
Управление разработкой
Управление рисками
Kanban
Scrum
Agile
Построение команды
Разработка ТЗ
Проектное планирование
PMBOK