Результати пошуку за запитом: mvc 5*
Як я побудував проект на Django, Django REST Framework, Angular 1.1.x та Webpack
Автор: Редакция ITVDN
Моя идея состояла в том, чтобы построить простой репликабельный проект на Angular с бэкэндом на Django. Я искал и не смог найти нужных решений, пришлось во всем разбираться самому. В итоге я разобрался и решил сам написать гайд для всех, кого может заинтересовать данная проблема.
Данная статья поможет вам построить простое приложение Angular с бэкэндом на Django, организованного с помощью Webpack.
Проблема
Я хочу настроить проект на Angular 1.1.x и скормить ему данные с сервера Django. Мне бы хотелось использовать Django REST Framework (DRF), чтобы пострить RESTful API. Я также хочу сбандлить JS ассеты. Сейчас я собираюсь запустить сайт на одном сервере.
Предварительные требования
Python 2.x
Django 1.9.x
npm 2.15.8+
Webpack 1.13.x (sudo npm i -g webpack)
ESLint 2.13.1+ (sudo npm i -g eslint)
NodeJS 4.4.7+
Содержание
Скаффолдинг проекта. Создайте свои начальные директории.
Скаффолдинг проекта на Django.
Настрока переменных среды, нужных для запуска сервера Django.
Установка Django REST Framework и настройка Django с использованием переменных среды.
Создание API.
Запуск Django сервера с использованием dev settings.
Инициализация npm-пакета и установка front-end JS зависимостей.
Создание Angular entry-point и загрузка начальных зависимостей.
Настройка Webpack'а.
Дайте команду Django загрузить приложение.
Создайте шаблон базы приложения Angular.
Напишите компонент home.
Напишите Angular роуты, ведущие к вашему компоненту home и странице 404.
Добавьте директивы ангуляр-маршрутизатора к шаблону входной точки приложения.
Проверьте ваше REST API в приложении Angular. Шпаргалка.
Итак, начнем!
0. Настройте среду для Python.
mkvirtualenv mysite
1. Скаффолдинг проекта на Django. Создайте начальные директории.
Мы хотим сфокусироваться на модулярности в ходе разработки. Следовательно, существует множество директорий в конечном итоге использования. Мы хотим, чтобы наше дерево изначально выглядело так:
mysite
├── backend
│ ├── docs
│ ├── requirements
└── frontend
├── app
│ ├── components
│ └── shared
├── assets
│ ├── css
│ ├── img
│ ├── js
│ └── libs
├── config
├── dist
└── js
Сделайте следующее:
mkdir mysite && cd mysite
mkdir -p backend/docs/ backend/requirements/ \
frontend/app/shared/ \
frontend/app/components/ \
frontend/config \
frontend/assets/img/ frontend/assets/css/ \
frontend/assets/js/ frontend/assets/libs/ \
frontend/dist/js/
*Примечание: Структура этого проекта была навеяна опытом с несколькими другими проектами. Я считаю эту организацию идеальной, но вам не обязательно ей следовать. Но, пока вы читаете этот гайд, вы должны придерживаться этой структуры.
2. Скаффолдинг проекта на Django.
В директории backend/ создайте Django проект:
python django-admin.py startproject mysite
Также создайте requirements.txt:
pip freeze > requirements/requirements.txt
В директории (вашего проекта) backend/mysite/ произведите скаффолдинг директории, той, где будет жить ваше API:
mkdir -p applications/api/v1/
touch applications/__init__.py applications/api/__init__.py \
applications/api/v1/__init__.py applications/api/v1/routes.py \
applications/api/v1/serializers.py applications/api/v1/viewsets.py
Теперь создайте структуру директории настроек:
mkdir -p configlord/settings/
touch configlord/settings/__init__.py \
configlord/settings/base.py configlord/settings/dev.py configlord/settings/prod.py \
configlord/dev.env configlord/prod.en
3. Настройте переменные окружения, которые нужны для запуска сервера Django.
На этом этапе я предпочитаю пользоваться django-environ для работы с переменными окружения. Существует множество способов сделать это, но пакет django-environ чрезвычайно упрощает этот процесс, поэтому я использую его во всех своих проектах.
Установите django-environ:
pip install django-environ
В mysite/dev.env добавьте следующее:
DATABASE_URL=sqlite:///mysite.db
DEBUG=True
FRONTEND_ROOT=path/to/mysite/frontend/
SECRET_KEY=_some_secret_key
Мы собираемся использовать эти переменные среды в наших настройках. Выгода от использования наших переменных окружения в отдельных файлах состоит в основном в том, что такая настройка позволяет облегчить переключение между средами. В нашем случае файл the dev.env является списком переменных, которые мы бы использовали в локальной среде разработки.
*Примечание: SECRET_KEY можно взять из settings.py, который был сгенерирован django-admin.py startproject.
4. Установите Django REST Framework и настройте Django, используя переменные среды.
Установка DRF:
pip install djangorestframework
Наполните settings/base.py следующим:
Укажите, где искать переменные окружения.
import environ
project_root = environ.Path(__file__) - 3
env = environ.Env(DEBUG=(bool, False),)
CURRENT_ENV = 'dev' # 'dev' is the default environment
# read the .env file associated with the settings that're loaded
env.read_env('./mysite/{}.env'.format(CURRENT_ENV))
Установите базу данных. В данном случае мы собираемся использовать встроенные в django-environ настройки SQLite.
DATABASES = {
'default': env.db()
}
Установите SECRET_KEY ,а также debug.
SECRET_KEY = env('SECRET_KEY')
DEBUG = env('DEBUG')
Добавьте DRF в пул приложений, которые Django должен использовать.
# Application definition
INSTALLED_APPS = [
...
# Django Packages
'rest_framework',
]
Ссылки будут «жить» в специальном URL модуле, созданном с помощью базы проекта.
ROOT_URLCONF = 'mysite.urls'
Укажите Django, где искать все шаблоны и другие статические ассеты.
STATIC_URL = '/static/'
STATICFILES_FINDERS = [
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
]
STATICFILES_DIRS = [
env('FRONTEND_ROOT')
]
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [env('FRONTEND_ROOT')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
В соответствии с настройкой TEMPLATES Django должен будет искать шаблоны внутри frontend/ directory. Это то, где Angular приложение будет жить. Мы используем только Django, чтобы обслужить шаблон, внутри которого Angular приложение будет загружаться, которое будет выполнено через entry-point директиву. Если вы не знаете, о чем я, продолжайте чтение...
Наполните settings/dev.py:
from mysite.settings.base import *
CURRENT_ENV = 'dev'
Здесь мы указываем, что этот файл настроек унаследывает настройки из base.py и переопределяет строку CURRENT_ENV, найденную в base.py. Мы говорим: «Используй это значение вместо значения, найденного в наследуемом модуле».
5. Создайте API.
Нам нужно нечто, с помощью чего мы сможем протестировать службы Angular, поэтому давайте создадим небольшое API. Этот шаг можно пропустить, но я не советовал бы делать этого. Нам важно знание того, что настройки приложения Angular работают исключительно с точки зрения его потенциала, чтобы облегчить HTTP запросы.
Сгенерируйте приложение.
manage.py startapp games
Создайте модель в games/models.py.
class Game(models.model):
title = models.CharField(max_length=255)
description = models.CharField(max_length=750)
Создайте DRF сериализатор для модели игры в applications/api/v1/serializers.py.
from rest_framework.serializers import ModelSerializer
from applications.games.models import Game
class GameSerializer(ModelSerializer):
class Meta:
model = Game
Создайте DRF viewset для модели в приложениях applications/api/v1/viewsets.py.
from rest_framework import viewsets
from applications.games.models import Game
from applications.api.v1.serializers import GameSerializer
class GameViewSet(viewsets.ModelViewSet):
queryset = Game.objects.all()
serializer_class = GameSerializer
В applications/api/v1/routes.py зарегистрируйте роуты, используя DRF's router registration features.
from rest_framework import routers
from applications.api.v1.viewsets import GameViewSet
api_router = routers.SimpleRouter()
api_router.register('games', GameViewSet)
Обозначьте ссылки для зарегистрированного DRF роута внутри mysite/urls.py:
from django.contrib import admin
from django.conf.urls import include, url
from applications.api.v1.routes import api_router
urlpatterns = [
url(r'^admin/', admin.site.urls),
# API:V1
url(r'^api/v1/', include(api_router.urls)),
]
6. Запустите сервер Django, используя dev settings.
manage.py runserver --DJANGO_SETTINGS_MODULE=mysite.settings.dev
Впуская DJANGO_SETTINGS_MODULE в runserver, мы «говорим» - работать используя специфические параметры.
Если все работает, у вас появится возможность открыть localhost:8000/api/v1/games и увидеть ответ от DRF. Если все работает – самое время заняться построением приложения Angular. Если нет – направьте автору проблему. Если вы застряли на этом этапе – оставьте комментарий автору под оригиналом публикации.
7. Инициализируйте npm-пакет и установите front-end JS зависимости.
Приложение Angular не будет работать так, как мы хотим, если правильные зависимости не будут установленны. Самое время установить базовые пакеты, которые понадобятся.
Инициализируйте npm-пакет. Прямо из frontend/ запустите
npm init --yes
By passing the --yes flag into init, you're telling NPM to generate a package.json using NPM defaults. Otherwise, if you don't pass that in, you'll have to answer questions... Boring.
Установите dev dependencies.
npm install --save-dev eslint eslint-loader
Установите общие зависимости.
npm install --save eslint eslint-loader angular angular-resource angular-route json-loader mustache-loader lodash
Файл package.json file во frontend/ должен выглядеть приблизительно следующим образом:
{
"name": "my-app",
"version": "0.0.1",
"description": "This is my first angular app.",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"eslint": "^3.1.1",
"eslint-loader": "^1.4.1"
},
"dependencies": {
"angular": "^1.5.8",
"angular-resource": "^1.5.8",
"angular-route": "^1.5.8",
"eslint": "^3.1.1",
"eslint-loader": "^1.4.1",
"json-loader": "^0.5.4",
"lodash": "^4.13.1",
"mustache-loader": "^0.3.1"
}
}
Здесь то, что мы только что установили:
eslint – отличный линтер, благодаря которому код JavaScript будет в порядке (последователен).
eslint-loader – для запуска eslint через Webpack. Чуть позже я объясню концепцию «загрузчиков».
angular - MVC фреймворк. Если вы не знали об этом, стоит подумать о том, чтобы закрыть эту страничку прямо сейчас.
angular-resource - (Angular) HTTP библиотека выбора. Это абстракция $http.
json-loader - загрузчик (снова, используемый Webpack) для распаковки JSON из .json файлов с помощью require() во время работы нашего приложения.
mustache-loader – загрузчик, который мы будем использовать, чтобы парсить наши mustache шаблоны. Mustache шаблоны – это веселье.
Я могу спокойно предположить, что вы не знаете, как все эти пакеты заиграют вместе.
Не переживайте, братишки.
8. Создайте entry-point в Angular, объявите начальные зависимости, объявите первоначальные глобальные переменные.
В frontend/app/app.js добавьте следующее:
/* Libs */
require("angular/angular");
require("angular-route/angular-route");
require("angular-resource/angular-resource");
/* Globals */
_ = require("lodash");
_urlPrefixes = {
API: "api/v1/",
TEMPLATES: "static/app/"
};
/* Components */
/* App Dependencies */
angular.module("myApp", [
"ngResource",
"ngRoute",
]);
/* Config Vars */
// @TODO in Step 13.
/* App Config */
angular.module("myApp").config(routesConfig);
app.js это то, где Webpack будет искать модули, чтобы бандлить их вместе. Лично я ценю такую организацию и методику вызовов, но такой порядок не обязателен. Существует 6 секций:
Libs – главные библиотеки, используемые на протяжении работы Angular приложения;
Globals – зарезервированные глобальные переменные, которые мы можем использовать во время работы приложения;
Components (Компоненты) – особенные модули проекта;
App Dependencies (Зависимости приложения) – объявление входной точки приложения и его зависимостей;
Config Vars – переменные, где хранятся настройки, такие как route config;
App Config - вводит configs (настройки) в приложение, используя сохраненные из предыдущей секции.
Для того, чтобы globals работали, вам следует указать ESLint на то, какие из переменных - глобальные.
В config/eslint.json добавляем следующее:
{
"env": {
"node": true
},
"extends": "eslint:recommended",
"rules": {
"indent": [
"error",
2
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"double"
],
"semi": [
"error",
"always"
],
"no-console": 0
},
"globals": {
"_": true,
"_urlPrefixes": true,
"angular": true,
"inject": true,
"window": true
},
"colors": true
}
Ниже несколько переменных, о которых мы предупредили ESLint:
_ представить lodash.
_urlPrefixes – объект, который мы будем использовать в приложении для гиперссылок. Я расскажу об этом позже.
angular, чтобы представить AngularJS object driving our entire application.
inject, который будет использоваться для ввода зависимостей Angular.
window, которая просто представляет объекты окон в JavaScript, является представителем DOM.
9. Настройка Webpack.
Теперь, когда мы выложили большинство наших зависимостей приложения, мы можем построить config file для Webpack. Webpack будет консолидировать все зависимости, а также модули для приложений, которые мы создаем в один файл. В bundle.
В frontend/webpack.config.js добавляем следующее.
module.exports = {
entry: "./app/app.js",
output: {
path: "./dist/js/",
filename: "bundle.js",
sourceMapFilename: "bundle.js.map",
},
watch: true,
// eslint config
eslint: {
configFile: './config/eslint.json'
},
module: {
preLoaders: [{
test: /\.js$/,
exclude: /node_modules/,
loader: "eslint-loader"
}],
loaders: [
{ test: /\.css$/, loader: "style!css" },
{ test: /\.html$/, loader: "mustache-loader" },
{ test: /\.json$/, loader: "json-loader" }]
},
resolve: {
extensions: ['', '.js']
}
};
Для того, чтобы Webpack бандлил все наши статические зависимости, нам нужно указать ему, где их брать, какие зависимости обрабатывать и как управлять ими до банлинга.
Давайте посмотрим на то, что указывает Webpack с помощью webpack.config.js:
Entry - это путь к тому, что Webpack'у нужно для старта бандлинга. Это можеть быть полный путь или путь, относительный тому, где webpack.config.js располагается. В данном случае мы говорим о последнем варианте.
output - это объект, содержащий в себе path, который является директорией, в которую связанные зависимости будут помещаться; filename - это название бандла; и, в данном случае, мы решили использовать sourceMapFilename, чтобы обозначить, что наша() source map будет вызван(а).
watch указывает Webpack следить за изменениями в файле, пока он выполняется. Если это не настроено как true, Webpack прогонит процесс бандлинга единожды и остановится.
eslint содержит в себе специфические ESLint настройки, используемые eslint-loader.
module указывает Webpack'у, что делать с модулями, с которыми он работает.
module.preLoaders «говорит», что делать перед бандлингом. В данном случае мы хотим запустить модули (исключив модули установленные npm) через eslint.
module.loaders - это то, где указана последовательность загрузчика. В нашем случае мы просто настраиваем test и loader, где test указывает Webpack’у, какие модули запускать в загрузчике (по соответствию с паттерном regex), и loader говорит Webpack’y, какой загрузчик использовать в модулях, которые соответствуют regex паттерну в test. Каждый загрузчик указан в строке и разделен восклицательным знаком. Ex: loader!another_loader!yet_another_loader
module.preLoaders указывает, какие preLoaders'у запускать модули. Используемые настройки такие же точно, какие мы использовали в module.loaders.
Но, Грег, какая разница между preLoaders и loaders? Я рад, что ты спросил, мой дорогой друг!!
A loader указывает Webpack'у, как бандлить требуемые файлы. Loader смотрит на модуль и говорт: «Эй, так как вы упаковываете это в один файл как строку – это то, как оно должно быть преобразованно для bundle'а».
A preLoader обрабатывает код перед loaders, например, чтобы слинтить JavaScript модули.
A postLoader является плагином Webpack'а, который обрабатывает код после бандинга. Мы не специфицировали ни один postLoader ради простоты.
10. Укажите Django загрузить приложение.
Прямо сейчас все, что нужно сделать – указать Webpack’у что создавать, как создавать и что должно быть создано. (На данном этапе я бы очень удивился, если вы попробуете запустить его и он заработает без ошибок. Если так и есть, я чертов мужик.)
Так как Django использует свой собственный URL процессор в нашем приложении, мы можем быть рады тому, как любезно Django управляет всем тем, что введено в строку браузера пользователя. Как бы то ни было, мы бандлим одностраничное приложение, используя абсолютно другой фреймворк, и хотим, чтобы у приложения был полный контроль над тем, что пользователь вводит. Все, что нам нужно – обслуживать одну страничку, в которой работает SPA. Следовательно...
В backend/mysite/mysite/urls.py добавляем в список urlpatterns следующее:
# Web App Entry
url(r'^$', TemplateView.as_view(template_name="app/index.html"), name='index'),
Это значит, что когда пользователь открывает mysite.com/, env('FRONTEND_ROOT') + app/index.html будет находить STATICFILES_FINDERS в порядке рендера HTML шаблона.
11. Создайте шаблон базы приложения Angular.
frontend/app/components/app/index.html шаблон должен выглядеть как обычный шаблон Django.
В frontend/app/index.html добавляем следующее:
{% load staticfiles %}
<html ng-app="myApp">
<head>
<title>My Sitetitle>
<script src="{% static 'dist/js/bundle.js' %}">script>
head>
<body>
body>
html>
В таком случае вам удастся запустить Webpack. Если вы запустите Django сервер и откроете localhost:8000,вы увидите пустую страничку. Если нет – дайте знать автору.
12. Напишите home component.
Давайте напишем наш первый компонент. Он отобразит текст на страничке, пока пользователь открывает localhost:8000.
Создайте директорию для компонента и базовые файлы. В frontend/app/components/:
mkdir home && touch home/home-controller.js home/home.js home/home.html
В frontend/app/components/home/home.html добавляем следующее:
<div ng-controller="HomeController as ctrl">
<div>
<h1>Home!h1>
div>
div>
Теперь добавим следующее в frontend/app/components/home/home-controller.js:
function HomeController() {
var that = this;
that.foo = "Foo!";
console.log(that); // should print out the controller object
}
angular.module("Home")
.controller("HomeController", [
HomeController
])
Определение модуля Angular должно быть объявлено в home.js:
angular.module("Home", []);
require("./home-controller");
Теперь мы можем сослаться на "Home" в области зависимости определения модуля. Давайте сделаем это!
В app/app.js добавьте следующее:
/* Components */
require("./components/home/home");
/* App Dependencies */
angular.module("myApp", [
"Home", // this is our component
"ngResource",
"ngRoute"
]);
13. Пропишите пути Angular'а, ведущие к home component и страничке 404.
Нам нужно настроить первый путь. Когда пользователь попадает на localhost:8000, Angular должен взять контроль над загрузкой отрендеренного шаблона. Чтобы сделать это, нам потребуется использовать angular-router.
В frontend/app/routes.js пишем следующее:
function routesConfig($routeProvider) {
$routeProvider
.when("/", {
templateUrl: _urlPrefixes.TEMPLATES + "components/home/home.html",
label: "Home"
})
.otherwise({
templateUrl: _urlPrefixes.TEMPLATES + "404.html"
});
}
routesConfig.$inject = ["$routeProvider"];
module.exports = routesConfig;
Если мы не добавим _urlPrefixes.TEMPLATES, angular-router предположит, что components/home/home.html является действительной ссылкой, которую узнает сервер. Так как STATIC_URL в настройках предполагает неправильную работу localhost:8000/components/home/home.html.
Также, если вы еще не заметили, вы увидите otherwise({...}) в коде роутов. Это то, как будут реализованы страницы 404.
В frontend/app/404.html добавляем следующее:
<h1>NOT FOUNDh1>
И в завершении добавляем frontend/app/app.js:
/* Config Vars */
var routesConfig = require("./routes");
14. Добавьте директивы angular-router к шаблону точки входа приложения.
А теперь нам нужно указать Angular, где будет происходить переключение отображаемого, когда пользователь пользуется навигацией. Чтобы сделать это, мы используем всю силу angular-router.
В тэг
в frontend/app/index.html добавляем:
<base href="/">
Теперь в тэг
добавляем:
<div ng-view>div>
Ваш index.html теперь должен выглядеть так:
{% load staticfiles %}
<html ng-app="myApp">
<head>
<title>My Sitetitle>
<script src="{% static 'dist/js/bundle.js' %}" >script>
<base href="/">
head>
<body>
<div>
<div ng-view>div>
div>
body>
html>
Запустите Webpack. Откройте localhost:8000. Вы должны увидеть, что произошло в home/home.html. (Если ничего, отправьте эти данные автору J ).
15. Проверьте REST API в приложении Angular.
Если все сделано, у вас появится возможность написать angular службы для Django API. Давайте создадим небольшой компонент, чтобы увидеть, можем ли мы это сделать. Этот компонент должен перечислять игры. Я предполагаю, что вы уже заполнили базы данных, следовательно запрос HTTP к localhost:8000/api/v1/games вернет список игр.
Создайте скаффолд компонент в frontend/app/components/:
mkdir -p game/list/ && touch game/list/game-list-controller.js game/list/game-list-controller_test.js game/game-service.js game/game.js game/game.html
Этот компонент будет перечислять игры.
Этот компонент должен перечислять игры. Я предполагаю, что вы уже заполнили базы данных, следовательно запрос HTTP к localhost:8000/api/v1/games вернет список игр.
В game/game-service.js:
function GameService($resource) {
/**
* @name GameService
*
* @description
* A service providing game data.
*/
var that = this;
/**
* A resource for retrieving game data.
*/
that.GameResource = $resource(_urlPrefixes.API + "games/:game_id/");
/**
* A convenience method for retrieving Game objects.
* Retrieval is done via a GET request to the ../games/ endpoint.
* @param {object} params - the query string object used for a GET request to ../games/ endpoint
* @returns {object} $promise - a promise containing game-related data
*/
that.getGames = function(params) {
return that.GameResource.query(params).$promise;
};
}
angular.module("Game")
.service("GameService", ["$resource", GameService]);
Обратите внимание на ссылку $resource, которую мы используем для того, чтобы настроить механизмы HTTP в нашей службе.
В game/list/game-list-controller.js:
function GameListController(GameService) {
var that = this;
/* Stored game objects. */
that.games = [];
/**
* Initialize the game list controller.
*/
that.init = function() {
return GameService.getGames().then(function(games) {
that.games = games;
});
};
}
angular.module("Game")
.controller("GameListController", [
"GameService",
GameListController
]);
В game/game.html:
<div ng-controller="GameListController as ctrl" ng-init="ctrl.init()">
<div>
<h1>Gamesh1>
<ul>
<li ng-repeat="game in ctrl.games">{{ game.title }}li>
ul>
div>
div>
В game/game.js:
angular.module("Game", []);
require("./list/game-list-controller");
require("./game-service");
Затем обратимся к компоненту в app.js:
/* Components */
require("./components/game/game");
/* App Dependencies */
angular.module("myApp", [
"Home",
"Game",
"ngResource",
"ngRoute"
]);
В конце концов, мы собираемся настроить роуты для списка игр, поэтому в frontend/app/routes.js добавьте следующее в объект $routeProvider:
.when("/game", {
templateUrl: _urlPrefixes.TEMPLATES + "components/game/list/game-list.html",
label: "Games"
})
Запустите Webpack снова. Все должно верно скомпилироваться. Если нет – дайте знать автору.
Откройте localhost:8000/#/games. Вы увидите список игр.
Сделано!
Это все.
Сомнения/Мысли
Но есть некоторые сомнения:
Глобальные переменные могут конкретно подставить вас, если вы не знаете, как с ними работать. Их локальное поведение не гарантирует того же на продакшене. Насколько я помню, их можно заставить работать, если правильно описан метод. Ваше приложение на Angular тесно связанно с Django. Поэтому ваше приложение не будет просто слиянием back- и фронтенда. Если ваш Django-RIP давно устарел, значит поменялись и маршруты, следовательно сконфигурируете ваш бэкенд согласно тому, как должны вести себя статические файлы. Так же вам будет необходимо заменить index.html с точкой входа Angular. Маленькие проекты не дадут вам особо попотеть, а вот большие явно заставят понервничать. Совет: единственное место, где должны сопрягаться приложение на Angular и Django сервер - это одна точка входа.
Деплоймент должен быть выполнен так же, как любой обычный деплоймент приложения.
Это все. Если у вас есть какие-либо вопросы и вы испытываете трудности, пожалуйста, оставьте их в комментариях в исходной статье!
Чит!
Автор пообещал выложить на гитхабе репозиторий со всем кодом.
Оригинальная статья на английском языке.
Введення в розробку програм під iOS. Частина 6
Автор: Volodymyr Bozhek
Здравствуйте, дорогие читатели.
В этом уроке мы:
Установим менеджер установки пакетов “Brew”;
Научимся пользоваться базой данных “Mongo DB” и изучим библиотеку “Mongoose”;
Установим и сконфигурируем базу данных “Mongo DB”;
Научимся запускать демон (службу) “Mongod” и подключаться к ней;
Научимся просматривать документы базы данных “Mongo DB” с помощью приложения “Robomongo”;
Создадим REST сервисы для товаров и пользователей с использованием “NodeJS”;
Научимся тестировать REST сервисы с помощью расширения “Chrome” браузера “Postman”;
Итак, вы скорее всего задались вопросом, почему же я выбрал именно такие технологии для написания REST сервисов. Почему не выбрал то, что уже давно у всех на слуху, такие технологии как Web API + Entity Framework. Ответ прост, я выбрал ровно те технологии, которые явно подходят платформе, на которой мы ведем разработку macOS.
Да, можно было установить Xamarin Community Edition, в нем создать ASP.NET проект и сделать сервисы на Mono.NET.
Еще был вариант сделать сервисы на виндовс платформе, развернутой на виртуальной машине в веб сервере IIS с сетевым адаптером мост. Это для того, чтобы веб сайт и сервисы были доступны на хостовой машине macOS в браузере.
Возможно, в одном из моих будущих видео курсов по разработке iOS приложений я буду использовать именно платформу Windows и Visual Studio для разработки REST сервисов.
Но в этом уроке мы будем делать сервисы на NodeJS, и вы сами убедитесь в том, насколько это просто и как мало кода надо для этого написать :)
В качестве среды разработки я буду использовать WebStorm, он довольно хорошо себя оправдал как один из продуктов JetBrains.
В этом уроке мы не будем работать с приложением “Warehouse” под iOS, поскольку мы должны приступить к изучению библиотеки “Alamofire”. А для нее необходимы REST сервисы, которых у нас сейчас нет. Показывать работу на всяких httpbin, parse и других сервисах тестирования я не буду, этого полно в сети интернет, вы и сами будете видеть это в поиске нужной вам информации.
“Alamofire” - это асинхронная сетевая библиотека для работы с REST сервисами. В большинстве туториалов не рассказывается, как сделать REST сервисы и клиент к ним на разных платформах.
Мне хотелось бы нарушить этот стереотип и предоставить вам учебные примеры по созданию полнофункционального REST сервиса и полнофункционального iOS клиента в составе приложения “Warehouse” к нему. Проще говоря, дать готовое решение для быстрого понимания, что и как делается.
Это то, чего обычно не хватает новичкам и то, чего обычно нигде не выкладывают. Приходится самостоятельно разбираться и искать нужную информацию.
Откройте “WebStorm”. Выберите в меню “File -> New Project”. Выделите тип проекта “Node.js Express App”.
В поле “Location” укажите название проекта “Warehouse” и путь, по которому вы будете сохранять данный проект.
В поле “Template” выберите “EJS”. Нажмите кнопку “Create”.
Вы увидите диалоговое окно с предложением, откуда взять библиотеку “NodeJS”.
Оставьте пункт по умолчанию “Download from the Internet” и нажмите кнопку “Configure”.
Будет загружен из сети интернет “NodeJS”, “Express” и другие библиотеки.
Панель навигации будет выглядеть у вас так:
Рассмотрим, что создал нам данный шаблон.
В папке “bin” хранится файл “www”, в нем находится настройка сервера “NodeJS”, с этого файла происходит запуск нашего сервера.
В папке “node_modules” находятся библиотеки, которые были автоматически загружены шаблоном проекта NodeJS.
В папке “public” находятся ресурсы, используемые нашим сервером (картинки, CSS стили, скрипты).
В папке “routes” находятся скрипты, которые должны содержать маршрутизацию относительно текущего URL, введенного пользователем.
Например, файл с именем “users.js” вызывется, когда пользователь введет в браузере URL: “http://localhost:{port}/users”.
Файл “index.js” вызывется, когда пользователь введет URL: “http://localhost:{port}”.
Если сравнивать с паттерном MVC (Model View Controller), то в папке “routes” находятся “контроллеры”.
В папке “views” находятся представления. Расширение “*.ejs” говорит о том, что содержимое данного файла будет транслироваться через библиотеку “Express JS”.
Данная библиотека создана в помощь, чтобы можно было проще создавать маршрутизацию в NodeJS и проще создавать пользовательский интерфейс.
Внутри этих файлов “*.ejs” содержится обычная “HTML” разметка. Файл маршрутизации и файл представления должны называться одинаково, если они будут связаны.
В текущем проекте связаны только “index.js” и “index.ejs”. Маршрут “users.js” не имеет явного представления, для него преставление генерируется средствами “NodeJS”.
Наша задача создать только REST сервисы, поэтому работу с “EJS” мы не будем рассматривать в данном уроке.
Рассмотрим содержимое файла “www” в папке “bin”.
На 7 строке через библиотеку “Require JS” мы подключаем содержимое модуля “app.js” в текущий исполняемый модуль “www” и запускаем это содержимое на исполнение.
В файле “app.js” содержатся настройки для работы нашего сервера.
На 8 строке мы задаем режим отладки для нашего сервера.
На 9 строке мы подключаем модуль “http” для работы с HTTP запросами.
На 15 строке задается порт “3000”, на этом порту сервер будет принимать входящие запросы к нему.
На 16 строке устанавливает этот порт для свойства “port” сервера.
На 22 строке создается сервер на основе настроек экземпляра “app”.
На 28 строке сервер запускается и начинает прослушивание на порту “3000”.
На 29 строке привязывается функция “onError”, вызываемый при возникновении ошибок.
На 30 строке привязывается функция “onListening”, вызываемая при начале прослушивания запросов сервером.
Остальной код в данном модуле не представляет для нас интереса.
Чтобы запустить приложение, выполните в меню “Run -> Run bin/www”, сервер запустится.
Затем откройте браузер и введите URL: “http://localhost:3000”, вы увидите приветствие.
Чтобы остановить сервер, выполните в меню “Run -> Stop”.
Теперь необходимо установить базу данных “Mongo DB”. Подробнее об установке вы можете прочитать тут. Проще всего устанавливать базу данных через менеджер пакетов “Brew”.
Давайте установим его. Перейдите в браузере по адресу, на сайте будет предложено скопировать строку “/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)” в терминал.
Откройте терминал и скопируйте в него строку установки “Brew”. После установки вы увидите следующее:
Теперь необходимо установить базу данных “Mongo DB”. Установка базы данных через “Brew” проще тем, что “Brew” сам заполняет нужные переменные среды окружения и вам не надо этого делать вручную в случае с установкой базы данных вручную.
Перейдите в “WebStorm”, откройте внутри него терминал. И введите команду “brew install mongodb && mongod”, данная команда скачает и установит “Mongo DB”, а также выполнит настройки по умолчанию для демона “mongod”.
Выполните в терминале команду “sudo mkdir -p /data/db”. Введите свой пароль и нажмите кнопку “Enter”. Данная команда создаст папку “data” и в ней папку “db”, эта папка используется по умолчанию для добавления базы данных “Mongo DB”.
Команда “sudo” используется, чтобы выполнить остальную часть команды от имени администратора.
Теперь необходимо установить в наш проект библиотеку “Mongoose” для осуществления возможности работы с базой данных их кода приложения сервера .
Выполните в терминале команду “npm install mongoose”. Документацию по этой библиотеке можно почитать тут:
Данную команду мы выполняли через встроенный в NodeJS менеджер пакетов, так как устанавливаем данную библиотеку исключительно для нашего проекта, а не глобально.
Откройте терминал, введите команду “mongod”.
Данная команда запускает сервер базы данных “Mongo DB”, который принимает входящие подключения на порту “27017”. На картинке выше вы можете в этом убедиться “waiting for connections on port 27017”.
Демон запустили, теперь перейдите в “WebStorm”, в терминале внутри введите команду “mongod –version”, вы увидите версию базы данных “Mongo DB”, которая была установлена на ваш компьютер.
Теперь необходим клиент с GUI для работы с базой данных. Откройте браузер, перейдите по адресу, нажмите кнопку “Download”, скачайте и установите приложение.
После установки приложения откройте его. Нажмите на иконку:
Откроется приложение “Robomongo”.
Нажмите кнопку “Connect to local or remote Mongo DB instance”. Откроется диалоговое окно подключения к базе данных.
Нажмите кнопку “Create”. Откройте диалоговое окно настройки подключения к базе данных.
Заполните настройки, как показано на картинке выше и только на вкладке “Connection”, нажмите кнопку “Save”. После этого в окне “Mongo DB connections” у вас появится добавленное подключение. Выделите его и нажмите кнопку “Connect”.
Нажмите правой кнопкой в панели навигации по “Warehouse” и в контекстном меню выберите пункт “Create Database”.
В поле “Database Name” введите “warehouse”, нажмите кнопку “Create”.
На картинке выше видно, что база данных “warehouse” была успешно добавлена.
Супер :)
Теперь надо добавить в проект модель и схему базы данных, они создаются с помощью библиотеки “Mongoose”.
Перейдите в “WebStorm”. В панели навигации, нажмите правой кнопкой по “Warehouse”, в контекстном меню выберите “New -> Directory”. Создайте папку с именем “models”.
Создайте в папке “models” модули “Product.js” и “User.js”. А в папке “routes” создайте модули “auth.js”, “products.js”.
Откройте модуль “Product.js”, заполните его, как показано на картинке ниже:
На 1 строке мы подключаем библиотеку “mongoose” и создаем ее экземпляр с именем “mongoose”.
На 2 строке мы правым операндом создаем схему таблицы товаров и присваиваем ее левому операнду с именем “ProductSchema”. Таблица товаров содержит поля:
скрытое поле “_id”, типа “String”, в этом поле содержится уникальный идентификатор строки.
скрытое поле “__v”, типа “Number”, в этом поле содержится версия API по умолчанию 0. Версия API нужна для того, чтобы можно было менять реализацию сервисов и иметь несколько версий для обратной совместимости.
поле “productImage”, типа “String”, тут будет храниться название картинок из нашего проекта под iOS, названия от “tool001” до “tool012”.
поле “productName”, типа “String”, тут будет храниться название товара.
поле “productDescription”, типа “String”, тут будет храниться описание товара.
На 7 строке мы правым операндом создаем экземпляр модели с именем “Product” и указываем создать экземпляр на основе схемы, описанной в экземпляре “ProductSchema”. Библиотека “mongoose” создает данный экземпляр и присваивает его левому операнду.
Свойство “exports” содержит экземпляры объектов, которые будут доступны из модуля при подключении его через библиотеку “Require JS”.
Откройте модуль “User.js”, заполните его, как показано на картинке ниже:
На 1 строке мы подключаем библиотеку “mongoose” и создаем ее экземпляр с именем “mongoose”.
На 2 строке мы правым операндом создаем схему таблицы товаров и присваиваем ее левому операнду с именем “UserSchema”. Таблица пользователей содержит поля:
скрытое поле “_id”, типа “String”, в этом поле содержится уникальный идентификатор строки.
скрытое поле “__v”, типа “Number”, в этом поле содержится версия API по умолчанию 0. Версия API нужна для того, чтобы можно было менять реализацию сервисов и иметь несколько версий для обратной совместимости.
поле “userName”, типа “String”, тут будет храниться логин пользователя.
поле “userPwd”, типа “String”, тут будет храниться пароль пользователя.
поле “userDesc”, типа “String”, тут будет храниться описание пользователя.
На 7 строке мы правым операндом создаем экземпляр модели с именем “User” и указываем создать экземпляр на основе схемы, описанной в экземпляре “UserSchema”. Затем присваем созданный экземпляр свойству “exports” данного модуля.
Откройте модуль “auth.js”, заполните его в соответствии с содержимым ниже:
На 1 строке подключаем модуль “express” и создаем его экземпляр с именем “express”.
На 2 строке создаем экземпляр маршрутизатора запросов с именем “router”.
На 3 строке подключаем модуль “User.js” и создаем его экземпляр с именем “User”.
На 4 строке строим маршрут типа “http://localhost:3000/auth/”.
На экземпляре “router” вызываем функцию “post”. Вызов данной функции говорит, что созданный с помощью него маршрут будет доступен только через HTTP глагол POST. Первым аргументом задаем маршрут, вторым аргументом задаем функцию обработчик, который будет вызван при переходе по данному маршруту с учетом заданного HTTP глагола. Т.е. когда пользователь отправит POST запрос по адресу.
Функция обработчик принимает три аргумента.
Первый аргумент “request” содержит экземпляр запроса по данному маршруту. Второй аргумент “response” содержит экземпляр ответа по запросу по данному маршруту. В этот экземпляр можно добавлять любой ответ, который вы хотите, чтобы пользователь получил.
Третий аргумент “next” содержит текущий итератор в стеке запросов по маршрутизации. Данный экземпляр необходим, чтобы была возможность перейти на следующую итерацию в стеке маршрутизации.
Сам по себе сервер NodeJS работает асинхронно и никогда никого и ничего не ждет, это нужно учитывать при работе с ним.
На 5 строке мы выводим сообщение на консоль.
На 6 строке мы на экземпляре “User” вызываем функцию “find”, в которую единственным аргументом передаем специальную функцию обработчик, в которой будет содержаться результат данной операции. Функция “find” получает все записи из таблицы “User” и присваивает их в JSON формате второму аргументу функции обработчика с именем “data”.
Для примера, в “data” может содержаться такой JSON:
“[{_id:'789787sdfsd78sdfsd7', __v:0, userName: “Test1”,...},{_id:'4444447sdfsd78sdfsd7', __v:0, userName: “Test2”,...}]”.
Где квадратные скобки - это массив, а в фигурных скобках - это экземпляр JSON.
В аргументе “err” содержится экземпляр ошибки, если произошла ошибка при выполнении данной функции “find”.
На 7 строке мы создаем экземпляр объекта с именем “res”, данный объект содержит свойство “Error”, которое инициализировано значением по умолчанию “Authorization Error”. Как вы уже поняли, это текст ошибки, который вернется на клиент в случае ошибки авторизации клиента.
На 8 строке мы проверяем, если при получении данных через функцию “find” произошла ошибка и аргумент “err” не содержит значение “undefined”, мы обращаемся к экземпляру “next” и говорим серверу выполнить следующую итерацию маршрутизации и вернуть ошибку на клиент. На клиент средствами NodeJS будет возвращена “Stack Trace” ошибки.
На 9 строке, если ошибки не было, мы выполняем цикл foreach по массиву JSON объектов “data”. В функцию “forEach” передается специальная функция, которая содержит три аргумента.
Первый аргумент “item” содержит текущий итерируемый экземпляр JSON.
Второй аргумент “i” содержит позицию итератора и имеет тип Number.
Третий аргумент “data” содержит исходный массив объектов JSON, по которым проводится итерация.
На 10 строке мы задаем условие поиска пользователя по его имени и паролю в списке всех пользователей полученной функцией “find”. В условии сравниваются имя и пароль, которые пришли в POST запросе на сервер, с именем и паролем, полученным от функции “find”.
На 12 строке, если пользователь был найден, мы присваиваем экземляру “res” JSON объект найденного пользователя.
На 15 строке мы обращаемся к экземпляру ответа “response”, вызываем на нем функцию “json”, которая принимает данные и возвращает ответ на клиент в JSON формате. В аргумент данного метода мы передаем или экземпляр найденного пользователя, или экземпляр ошибки, что пользователь не найден и авторизация не удалась.
На 18 строке мы экспортируем из модуля экземпляр маршрутизации “router”.
Откройте модуль “index.js”. Заполните его в соответствии с содержимым ниже:
На 1 строке подключаем модуль “express” и создаем его экземпляр с именем “express”.
На 2 строке создаем экземпляр маршрутизатора запросов с именем “router”.
На 3 строке строим маршрут типа “http://localhost:3000/index/”, доступный через HTTP глагол GET.
На 4 строке, на экземпляр ответа вызываем функцию “render”. Данная функция возьмет представление, указанное в первом аргументе функции и вернет его на сторону клиента. Вторым аргументом задается словарь, в который можно добавить свойства со значениями, к которым можно будет обращаться со стороны представления.
На 6 строке мы экспортируем из модуля экземпляр маршрутизации “router”.
Откройте модуль “index.ejs”. Заполните его в соответствии с содержимым ниже:
Библиотека Express JS позволяет нам обращаться к свойствам, которые мы указали во втором аргументе метода “render” путем добавления следующей конструкции “<%= Название_Свойства %>”. На этапе отрисовки страницы данные конструкции будут заменены на значение указанного свойства.
Откройте модуль “products.js”, заполните его в соответствии с содержимым ниже:
На 1 строке подключаем модуль “express” и создаем его экземпляр с именем “express”.
На 2 строке создаем экземпляр маршрутизатора запросов с именем “router”.
На 3 строке подключаем модуль “Product.js” и создаем его экземпляр с именем “Product”.
На 4 строке строим маршрут типа “http://localhost:3000/products/”. Данный маршрут будет доступен по HTTP глаголу GET.
На 5 строке мы вызываем на экземпляре “Product” функцию “find”. Внутри функции мы проверяем, были ли ошибки, и возвращаем в ответе JSON массив со списком всех товаров.
На 10 строке строим маршрут типа “http://localhost:3000/products/”. Данный маршрут будет доступен по HTTP глаголу POST.
На 11 строке мы вызываем на экземпляре “Product” функцию “create”. Внутри функции мы проверяем, были ли ошибки, и возвращаем в ответе JSON объект успешно созданного товара.
На 16 строке строим маршрут типа “http://localhost:3000/products/{_id}” (например, “http://localhost:3000/products/789w66s2322kks4676s” ). Данный маршрут будет доступен по HTTP глаголу GET.
На 17 строке мы вызываем на экземпляре “Product” функцию “findById”. Из названия функции ясно, что функция выполняет поиск по идентификатору товара. Для поиска используется скрытое поле “_id” в модели “Product”, объявленной в модуле “Product.js”. Внутри функции мы проверяем, были ли ошибки, и возвращаем в ответе JSON объект успешно найденного товара.
На 23 строке строим маршрут типа “http://localhost:3000/products/{_id}” (например, “http://localhost:3000/products/789w66s2322kks4676s” ). Данный маршрут будет доступен по HTTP глаголу PUT.
На 24 строке мы вызываем на экземпляре “Product” функцию “findByIdAndUpdate”. Из названия функции ясно, что выполняется поиск товара по его идентификатору “_id”, затем, в случае если найден, обновляются все его поля, кроме скрытых полей. В ответе возвращается JSON объект успешно обновленного товара.
На 30 строке строим маршрут типа “http://localhost:3000/products/{_id}” (например, “http://localhost:3000/products/789w66s2322kks4676s” ). Данный маршрут будет доступен по HTTP глаголу DELETE.
На 31 строке мы вызываем на экземпляре “Product” функцию “findByIdAndRemove”. Из названия функции ясно, что выполняется поиск товара по его идентификатору “_id”, затем, в случае если найден, товар удаляется. В ответе возвращается удаленный JSON объект.
Откройте модуль “users.js”, заполните его в соответствии с содержимым ниже:
В модуле “users.js” я не вижу смысла расписывать подробно, что происходит, поскольку тут все то же самое, что и происходило в модуле “products.js”, рассмотренном выше. Разница только в том, что мы используем другую модель данных “User”. Опишу только доступные маршруты.
На 4 строке строим маршрут типа “http://localhost:3000/users/”. Данный маршрут будет доступен по HTTP глаголу GET.
На 10 строке строим маршрут типа “http://localhost:3000/users/”. Данный маршрут будет доступен по HTTP глаголу POST.
На 16 строке строим маршрут типа “http://localhost:3000/users/{_id}” (например, “http://localhost:3000/users/789w66s2322kks4676s” ). Данный маршрут будет доступен по HTTP глаголу GET.
На 23 строке строим маршрут типа “http://localhost:3000/users/{_id}” (например, “http://localhost:3000/users/789w66s2322kks4676s” ). Данный маршрут будет доступен по HTTP глаголу PUT.
На 30 строке строим маршрут типа “http://localhost:3000/users/{_id}” (например, “http://localhost:3000/users/789w66s2322kks4676s” ). Данный маршрут будет доступен по HTTP глаголу DELETE.
Откройте модуль “app.js”, обновите его в соответствии с содержимым ниже:
Конкретно в модуль “app.js” были внесены следующие изменения.
С 8 по 11 строку были подключены модули “index.js”, “users.js”, “products.js”, “auth.js”.
На 13 строке был подключен модуль “mongoose”.
На 14 строке мы задаем свойство “Promise” в значение “global.Promise”, чтобы начать обмениваться сообщениями с базой данной “Mongo DB”.
На 15 строке мы подключаемся к базе данных “Mongo DB” c названием “warehouse”, мы ее ранее создавали в приложении “Robomongo”. Источник данных “mongodb://localhost/warehouse” можно разбить так: “mongodb://” протокол взаимодействия (аналоги “http://”, “tcp://”, “file://”). “localhost” - это адрес машины, на которой хостится база данных. “warehouse” - имя базы данных.
На 16 строке метод “then” вызывается в случае успешного подключения к базе данных.
На 17 строке метод “catch” вызывается в случае сбоя подключения к базе данных.
С 33 по 36 строку мы задаем доступные глобальные маршруты, которые будет обрабатывать сервер. Надеюсь, все помнят разницу между сервером и сервисами, это не одно и то же.
Сервер - это просто приложение, которое внутри себя способно содержать различные ресурсы. Сервер может запускать внутри себя различные потоки для обработки данных.
Сервис - это функционал, который как раз запускается в отдельном потоке внутри сервера.
Сам по себе сервис без наличия приложения ,в котором его можно разместить, работать не будет. В случае с WebAPI сервером является Microsoft IIS или отдельно стоящее исполняемое приложение с функцией self хостинга.
Мы закончили написание сервера. Запустите демон “mongod” в терминале.
Запустите сервер. Вы увидите обновленное приветствие.
Я бы рекомендовал вам прослушать курс “Angular JS”, автор Дмитрий Охрименко. Это один из лучших курсов, которые я когда-либо слушал. После данного курса вы без особых проблем сможете сделать клиентскую часть для сервера на “Angular JS”.
Теперь давайте научимся тестировать наши REST сервисы. Тестировать сервисы можно и через Fiddler, но на macOS у него есть проблемы с отрисовкой и работой. Поэтому откройте браузер и перейдите по адресу.
“Postman” - это аналог “Fiddler”, доступный в качестве расширения для браузера “Google Chrome”.
После установки расширения “Postman” откройте его.
Выполним первый запрос к сервису “users” по HTTP глаголу GET.
Заполните поле адрес, выберите глагол “GET”, нажмите кнопку “Send”. Результат придет - пусто. Обратите внимание, что в терминале “WebStorm” тоже пишется логирование вызовов при обращения к сервисам.
Откройте приложение “Robomongo”, подключитесь к базе данных. Разверните папку “Collections” базы данных “warehouse”, выполните щелчок правой кнопкой мыши по таблице “users”, в контекстном меню выберите “View Documents”. В “Mongo DB” нет колонок, там есть всего одна колонка, в которой хранится JSON объект. Строки называются документами. Причем, в каждую строку одной таблицы можно класть абсолютно разный по структуре JSON объект. База данных позволяет такую операцию.
Видим, что данных нет, это не удивительно, ведь мы еще ничего не добавляли.
Давайте добавим. Перейдите в “Postman”, выберите глагол “POST”.
Выберите “Content-Type” - “x-www-form-urlencoded”. Внимание, через другие типы “form-data” “raw” работать не будет. Заданные свойства “userName”, “userPwd”, “userDesc” будут отправлены в запросе как JSON объект “{ userName: 'admin', userPwd: 'abc123!', userDesc: 'Administrator' }”. Нажмите кнопку “Send”. Придет ответ:
В ответе мы видим JSON объект модели “User”, созданной на сервере.
Перейдите в приложение “Robomongo”, выполните пункт контекстного меню “View Documents” на таблице “users”.
Отлично, у нас появился первый пользователь :)
Перейдите в “Postman”, выберите HTTP глагол “GET”. Нажмите кнопку “Send”. Вы увидите такой результат.
Обратите внимание на квадратные скобки, в ответе пришел массив JSON объектов, а не один объект.
Теперь давайте изменим пароль пользователю “admin”, на “12345678”. Нам понадобится идентификатор пользователя, выделите и скопируйте значение свойства “_id”.
Выберите HTTP глагол “PUT”. Обновите данные так, как показано ниже.
Обратите внимание на добавление идентификатора пользователя после основного маршрута “../users/”. Нажмите кнопку “Send”. В ответе получим старый JSON объект до внесения изменений.
Теперь для того, чтобы посмотреть измененный объект, воспользуемся сервисом , который возвращает пользователя по его идентификатору “_id”. Выберите HTTP глагол “GET”, обновите адрес, добавьте в конец адреса идентификатор пользователя. Нажмите кнопку “Send”. Получим такой результат.
Видим, что пароль пользователя был успешно обновлен и мы получили в ответе один JSON объект, а не массив пользователей.
Теперь попробуем удалить пользователя. Адрес оставьте тот же. Выберите HTTP глагол “DELETE” и нажмите кнопку “Send”.
Видим, что в ответе содержится JSON объект удаленного пользователя.
Теперь проверим, доступен ли пользователь после удаления. Адрес оставьте тот же. Выберите HTTP глагол “GET”, нажмите кнопку “Send”.
Видим, что пользователь действительно был удален. Также можете проверить это в приложении “Robomongo”.
Теперь приступим к тестированию сервиса “products”.
Получим список товаров.
Товаров нет. Добавим первый товар.
Обновим описание товара.
Получим обновленный товар по его идентификатору.
Удалим товар.
На этом мы завершаем урок.
К данной статье прикреплен архив с готовым сервером на NodeJS , в помощь учащимся :)
На следующем уроке мы:
выполним рефакторинг проекта “Warehouse” под “iOS”;
научимся пользоваться CollectionViewController;
научимся пользоваться библиотекой “Alamofire”, в конце урока будут доступны исходники полноценного рабочего приложения;
научимся сохранять объекты в настройки телефона и извлекать их;
реализуем функциональность для работы со всеми сервисами, созданными в данном уроке;
добавим представление регистрации;
добавим представление редактирования пользователей.
Материалы к статье тут.
5 міфів про програмування, які стримують новачків
Автор: Редакция ITVDN
Світ ІТ приваблює багатьох: висока зарплата, віддалена робота, цікаві завдання. Але перед тим як почати навчання, чимало людей зупиняються… через страх. І часто причина — у міфах, які давно не мають нічого спільного з реальністю.
У цій статті ми розвінчуємо п’ять найпоширеніших міфів, що заважають новачкам почати шлях у програмуванні.
Міф 1
«Щоб стати програмістом, треба бути математичним генієм»
Цей стереотип і досі лякає багатьох. Насправді ж для старту в ІТ потрібне логічне мислення, а не знання вищої математики.
Так, у деяких напрямках (наприклад, Data Science або GameDev) математика важлива. Але у Web-розробці, QA, DevOps, Backend-проєктах ти можеш працювати, навіть якщо в школі не любив алгебру. Факт: згідно з дослідженням IBM, 72% ІТ-фахівців мають гуманітарну освіту, а не технічну.
Міф 2
«Навчання триває роками»
Традиційна вища освіта — це 4-5 років, але в ІТ усе інакше. Онлайн-курси, буткемпи, інтенсиви — дозволяють отримати базу за 6–12 місяців.
На платформі ITVDN студенти вивчають HTML, CSS, JavaScript, Python або C# у своєму темпі та отримують практичні навички, які потрібні роботодавцям.Навіть після кількох місяців навчання можна знайти стажування або пройти тестове завдання.
Міф 3
«Програмування — це тільки для “ботаніків”»
Є уявлення, що програміст — це замкнена людина, яка говорить лише з комп’ютером. Насправді це творча і командна професія. В ІТ цінують комунікацію, ініціативу, вміння шукати рішення. Багато розробників починали як фітнес-тренери, вчителі, маркетологи або менеджери. Програмування — це навичка, яку може опанувати кожен.
Міф 4
«Без університету тебе ніхто не візьме»
Сучасні компанії цінують скили, а не дипломи. Якщо у тебе є GitHub, виконані проєкти, сертифікати, знання англійської — це вже дає перевагу на старті.
Більшість студентів ITVDN не мають ІТ-диплому, але після навчання успішно проходять співбесіди та отримують першу роботу. Під час рекрутингу найважливіше — практика, мислення і портфоліо, а не формальна освіта.
Міф 5
«Щоб стати програмістом, треба одразу знати всі мови»
Це один із найбільш шкідливих міфів. Насправді достатньо обрати одну мову для старту — і з неї побудувати фундамент.
Наприклад:
Python — чудовий для аналітики, автоматизації, бекенду
JavaScript — ідеальний для веб-розробки
C# / .NET — популярний для корпоративних застосунків
Потім ти зможеш додати інші мови, але спочатку важливо навчитися думати, як програміст.
Міфи — це психологічні бар’єри. Вони народжуються з незнання, чужого досвіду або застарілих уявлень.
А правда така:
✅ У програмування можна прийти з нуля
✅ Навіть якщо тобі далеко не 20
✅ Без технічної освіти
✅ І без “геніального” рівня IQ
Головне — мотивація, правильна програма та підтримка, які допоможуть пройти шлях від першого коду до першого оферу.
Топ-5 кращих фреймворків для Python-розробників
Автор: Редакция ITVDN
Сейчас трудно представить себе любого девелопера без использования фреймворков. Здесь вы найдёте 5 лучших и наиболее признанных фреймворков для Python-разработчиков.
Что такое framework?
Говоря простым языком, фреймворк — набор инструментов для программиста. Фреймворк существенно упрощает разработку за счёт готовых решений и чётко выделенной структуры разработки приложений, сайтов.
При использовании фреймворка вы значительно сэкономите себе время, ведь вам не придётся тратить его на решение рутинных задач программирования. Вместо этого вы сможете уделить внимание непосредственно разработке, сократив потраченное время с нескольких недель до пары дней.
При использовании framework’a вы будете совершать меньше ошибок из-за невнимательности, и ваш синтаксис станет лучше. Кроме того, каждый framework оснащён собственной системой безопасности, которая защитит вас от случайной поломки программы.
Большинство фреймворков являются бесплатными и имеют открытый код, хотя некоторые придётся покупать.
Представляем вашему вниманию 5 лучших фреймворков для разработки на Python.
Django
«Классический» Python-framework, Django серьезно упрощает разработку за счёт большого количества доступных функций и паттернов. Имеет открытый код и предлагает большое количество возможных решений.
Django относится к так называемым full-stack фреймворкам, которые универсальны и содержат все стандартные функции и шаблоны.
К ним относится: аутентификация, маршрутизация, миграция баз данных, ORM и прочие.
Django можно использовать для администрирования содержимого сайтов, аутентификации, RSS. Он отлично подойдёт для создания сайтов.
Фреймворк работает с основными БД: MySQL, SQLite, PostgreSQ, Oracle. При необходимости можно установить специальные драйверы для подключения других баз данных.
В целом этот фреймворк можно считать универсальным для Python-разработчиков. Он имеет большую базу шаблонов и на ура справляется со стандартными задачами, а также может помочь в решении нестандартных.
Имеет полностью переведённую на русский язык техническую документацию. С хорошим переводом.
Flask
Платный мини-фреймворк, который предоставляет прочную основу для создания веб-приложений. Вмещается в один файл и легко устанавливается, пригодится в создании мелких и средних проектов, но не подойдёт для крупных из-за недостатка шаблонов и готовых решений.
Предоставляет готовые шаблоны для маршрутизации, поддержку безопасных кукисов, WSGI 1.0. Имеет встроенный дебаггер и сервер для HTTP-разработки. Сервер поддерживает fapws3, GAEM, CherryPy, BJoem.
Pyramid
Бесплатный фреймворк типа «всё включено», разработан для приложений на основе Питона. Универсален и подойдёт как для создания небольших, так и больших проектов. Легок в установке, понятен, не тормозит. Имеет минималистичный дизайн.
Имеет большое количество готовых шаблонов, в основном рассчитанных на разработчиков API. Умеет генерировать URL, помогает при аутентификации и авторизации пользователей, удобен для создания однофайловых приложений. Отлично подходит для тестирования и отладки.
Twisted
Создан для решения специальных задач сетевых разработчиков. Быстр, бесплатен, сокращает время разработки сервисов в несколько раз. Создан на базе Deferred, которая упрощает обслуживание сетевых запросов и обработку ошибок. Одно из главных оружий сетевого разработчика.
Не подойдёт для разработки типичных веб-приложений из-за своих шаблонов и структуры. Twisted используется для разработки небольших асинхронных программ.
Поддерживает большинство сетевых форматов: TCP, UDP, SSL/TLS, Domain sockets; умеет работать с сетевыми протоколами: HTTP, NNTP, XMPP, IMAP, IRC, FTP, SSH и прочими. Ещё больше модулей и форматов можно подключить с помощью драйверов.
Имеет дополнительные структуры: Unit test (с поддержкой системы Deferred), Processor pools и т.д.
Tornado
Асинхронный фреймворк и одновременно сетевая библиотека по типу Twisted. Справляется с классической проблемой С10k (то есть может обрабатывать свыше 10 000 поступающих сетевых запросов). Представляет из себя солянку из Django, Flask и Twisted, но при этом быстрее их.
Имеет встроенные шаблоны для аутентификации и авторизации, с поддержкой внедрения других шаблонов (например, Google), не блокирующийся HTTP-клиент. Справляется с длинными запросами (long polling’ами), имеет поддержку web-сокетов.
Используется разработчиками, которые создают масштабные сетевые приложения с большой нагрузкой и высокими требованиями к производительности.
Каждый год количество новых фреймворков постоянно растёт, но некоторые из них уже несколько лет держатся на плаву, периодически изменяясь. Эти пять уже признаны чуть ли не классикой, и начать изучение мира фреймворков стоит именно с них. Потом вы сможете перейти на более специфические, предназначенные для решения определённых задач.
Если вы изучаете программирование на Python и хотите освоить самые популярные фреймворки, смотрите видеоуроки ITVDN для Python-разработчиков, а также смотрите записи вебинаров на YouTube канале ITVDN.
HTML 5.2 is done, HTML 5.3 is coming
Автор: Charles McCathie Nevile
На сегодняшний день W3C уже выпустило релиз 5.2. Это второй пересмотр HTML 5, который идет сразу за HTML 5.1, увидевшего свет в прошлом году. В 2014 году мы выразили желание устраивать «ревизию» HTML каждый год. Что же, похоже, наше желание было услышано.
Эта статья представляет из себя что-то наподобие обновленного мануала о том, что такое HTML. В прошлом году мы серьезно пересмотрели спецификацию. Мы ввели некоторые новые фичи и убрали то, что на данный момент не является частью современной веб-платформы (или то, что никогда не получало широкой гласности). Как всегда, мы также исправили некоторые замеченные баги спецификации, убедившись, что материал точно соответствует современному изменчивому веб-миру.
Было внедрено множество различных фичей. Благодаря Payment Request API процесс ведения коммерции в вебе стал значительно проще и позволил снизить риски, связанные с возможными ошибками в виде багов или невнимательностью оператора. Новые функции защиты, такие как Content Security Policy, защищают пользователей более эффективно, в то время как работа, проделанная в ARIA, помогает разработчикам создавать качественный функционал веб-сайтов специально для людей с ограниченными возможностями.
HTML 5.2 делает проверенную систему плагинов устаревшей. Новые технологии или возможности, такие как виртуальная реальность или скоростная передача, теперь разрабатываются как часть веб-платформы. Подобный подход позволяет обеспечить лучший контроль за системой безопасности, часто снижая стоимость разработки, и позволяет больше обращать внимание на создание сервисов, нежели на выбор платформы.
Новая документация и исправление багов подняли HTML на новый уровень. Обозначение main – элемента было улучшено для поддержки современных паттернов дизайна, элемент style теперь может быть использован внутри блока body. Численные ограничения на код были упразднены, в то время как некоторые для обеспечения лучшей безопасности наоборот – усилены. Теперь браузеры предоставляют лучшую поддержку для интернациональных email-адресов и позволяют людям писать письма на тех языках, которые они используют в повседневной жизни.
И это только несколько красноречивых примеров касательно того, как W3C улучшила HTML, дабы отображать запросы современного веб-рынка. Также существует ещё много изменений, больших и маленьких, в этом обновлении.
Вместе с этим обновлением мы передаем привет некоторым членам нашей команды, таким как Стив Фолкнер и Тревис Ляйтред, выступивших редакторами HTML 5.0, Аррон Айхольц – разработчикам новой кодовой структуры HTML 5.1. И также Алексу Данилу. Их вклад был воистину важным, и их усилия послужили строительным фундаментом для всех тех, кто продолжил совершенствовать спецификацию разметки HTML.
Также обратите свое внимание на First Public Working Draft HTML 5.3. Это была часть наших планов по созданию новой HTML-рекомендации в 2018 году. Кроме того, некоторые наши планы претерпели изменения, потому что мы стараемся отслеживать, нужно ли что-то изменить \ дополнить в спецификации согласно современным требованиям или нет. Мы стараемся улучшать работу с интернациональными особенностями, доступностью спецификации и учитываем все пожелания сообщества.
Сангван Мун продолжает работать как редактор. Кроме того, нашу команду пополнили такие люди, как Брюс Левсон, Патриция Аас, Шветанк Дихит, Ттеренс Еден и Ксяоиян Ву. Еще раз спасибо Стиву Фолкнеру за то, что остается с нами и работает над новыми версиями спецификации. Для нас честь иметь настолько интернациональную команду, и мы верим, что их профессионализм принесет свои плоды. И хотя всегда есть гора достаточно монотонной работы по поддержке технологии, я верю, что этот год будет воистину годом HTML.
Веб представляет из себя платформу для каждого, и то, что наша команда объединяет специалистов из великого множества стран, является свидетельством того, что наша работа не напрасна и мы вносим вклад в общее дело веб-разработки. Мы внимательно следим за обновлениями HTML и рады будем сообщать вам наиболее актуальную информацию.
Автор перевода: Евгений Лукашук
Оригинал статьи
Що нового в Angular 5
Автор: Дмитро Охріменко
Переход от AngularJS к Angular 2 был огромным шагом вперед. При этом изменилось абсолютно все, без обратной совместимости. В то же время, Angular 4 добавила новые возможности, но при этом была обратно совместимой с Angular 2 (Версия Angular 3 была пропущена из-за @angular/router, который на момент релиза был 3.x, в то время как остальные пакеты 2.x. Для того, чтобы избежать путаницы и перевести все пакеты к одной версии, третья версия была пропущена). Angular 5 - это следующее обновление, в котором изменения затронули механизмы, работающие «под капотом».
Многие пользователи ITVDN задают вопрос об актуальности учебных программ видеокурса Angular Essential, который записан с использованием версии 2 и видеокурса Angular Advanced (версия 4). Angular 5 не является чем-то абсолютно новым, это улучшение существующего Фреймворка. Чтобы понять и начать использовать возможности, которые появились в пятой версии, необходимо знать основы, которые не изменились, начиная со второй версии.
Что нового в Angular 5?
Улучшенный компилятор. В Angular 4 компилятор перекомпилировал все файлы при каждом изменении. В Angular 5 компилятор работает только с теми файлами, в которых есть изменения, а это значит, что время на компиляцию проекта в целом значительно снизилось.
Оптимизированная сборка. В Angular CLI при использовании production build совместно с версией Angular 5 по умолчанию будет применяться build optimizer, который с помощью семантического анализа кода приложения сможет значительно уменьшить его размер.
Акцент на упрощение разработки PWA (Progressive Web Apps). PWA - это приложения, которые объединяют в себе лучшее, что есть в веб-приложениях и лучшее, что есть в мобильных приложениях.
PWA работают независимо от выбранного браузера;
адаптируются под устройство - десктоп, планшет, телефон;
могут работать без подключения к Интернет или при перебоях со связью;
выглядят как приложение, установленное на устройство;
благодаря Service Worker содержат актуальную обновленную информацию;
являются безопасными, так как работают через HTTPS;
используют возможности, подобные push уведомлениям;
Installable – позволяют пользователю добавить приложение на домашний экран устройства.
Поддержка TypeScript 2.4. Angular 5 поддерживает версию TypeScript 2.4, что дает возможность использовать новые возможности TS: перечисления, основанные на строках, улучшения проверки типов при работе с generic-типами, week-type-detection и прочее https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-4.html
Pipes, адаптированные под локализацию. Обновленные Pipes для Date, Currency, Number и Percent, нет необходимости использовать i18n. https://github.com/angular/angular/blob/master/CHANGELOG.md#i18n-pipes
Новые события Router. Используя события ActivationStart и ActivationEnd или ChildActivationStart и ChildActivationEnd, можно организовать отображения индикаторов загрузки при смене маршрута.
HttpClient. Новый HttpClient был добавлен в версии 4.3, старый http клиент помечен как depreceted в новой версии. В Angular 6 старый клиент будет удален. Из преимуществ нового клиента можно выделить самостоятельное извлечение JSON без необходимости явного применения метода map и возможность применять interceptors. https://angular.io/guide/http
Валидация форм. Теперь при работе с формами, c помощью свойства updateOn, можно определить, в какой момент будет происходить проверка – на событие blur или submit (вместо проверки на каждое событие input).
Замена ReflectiveInjector на StaticInjector. Изменен механизм для внедрения зависимостей. Для нового StaticInjector не нужен полифил Reflect (но при использовании JIT данные полифил все равно нужно будет использовать), что может уменьшить размер приложения.
Angular CLI 1.5 использует Angular версии 5.
Улучшение NgZone. NgZone стала еще быстрее, также библиотеку можно отключить для применения другой библиотеки для улучшения производительности.
Улучшенный RxJS. Поддержка обновлена до версии 5.5.2 и выше. Поддержка новых pipable operators https://github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md
Angular 5 получился компактней и быстрее, чем его предшественники, и не обошелся без новых возможностей. Запуск следующей версии Angular планируется на 28 марта 2018 года. Будем ждать улучшений и новых возможностей от команды Angular.
5 помилок розробників, які руйнують їхню кар'єру
Автор: Редакция ITVDN
Это действительно пугающая мысль. Ведь сегодня Вы работаете, выполняете задания, развиваетесь, а завтра вас «попросят»? Словно ваш труд не имел никакого значения. Как же это могло произойти? Что пошло не так?
Разработчики проходят через это каждый день.
Большинство разработчиков ничего не украли у своих работодателей, они не сделали ничего неэтичного, они были приятными и дружелюбными. Когда их просили о помощи, они всегда шли навстречу.
Так чего еще хочет работодатель?! Как оказалось, намного больше.
И вот разработчики уволены. Никто не указал им на конкретные ошибки, которые им нужно было бы избежать. Поэтому большинство продолжает совершать те же самые ошибки, сжигая мосты и разрушая свою карьеру.
Совершаете ли вы какие-либо из этих ошибок?
1. Доверять своим клиентам, чтобы понять их потребности
При разработке приложения ваши клиенты (читайте ваш работодатель) редко начинают с четкого представления о том, что им нужно. Все расплывчато и неясно.
Как вам известно, именно с этого и начинается большинство приложений, проектов и идей. Вы можете не знать, что вашему клиенту нужен особый подарок – им нужно понимание.
Поэтому вам необходимо сделать выбор. Каким разработчиком вы собираетесь стать? Вы Исполнитель, который просто делает то, что ему говорят? Или вы являетесь Незаменимым консультантом, на которого полагается ваша команда?
Потому что Исполнители заменяемы.
Работодатели находят разработчика, который может выполнять работу. Они говорят ему, чего хотят, и разработчик делает это. Простая формула, да?
Пока ваш клиент не найдет кого-то еще.
Того, кто может сделать то же самое, но быстрее и за меньшие деньги. Неудивительно, что большинство разработчиков программного обеспечения становятся неконкурентоспособными к моменту, когда они достигают 40 лет.
Может быть, работодатели думают, что это дело для молодых
Или что люди старше 40 лет устарели
Возможно, эти разработчики не знакомы с новой технологией
Слишком много разработчиков являются простыми Исполнителями. Если вы Исполнитель – причина увольнения не имеет значения. В какой-то момент вашей карьеры вы просто будете навсегда заменены.
С другой стороны, незаменимыми консультантами являются... Незаменяемые.
Такие разработчики дают своим клиентам понимание, в котором те нуждаются. Когда проект на старте, такие разработчики стремятся вникнуть в суть. Они спрашивают о пользователях и особенностях, которые клиенты хотят видеть в проекте, спрашивают об их мотивации, обо всем, что только может прийти в голову.
Такие разработчики ценятся везде, где бы они ни находились.
Они рок-звезды на работе
Или они вносят свой вклад в сообщество с открытым исходным кодом
Часто они учат и обучают других
Куда бы они ни пошли, они отдают и помогают другим. Такое отношение создает огромный контраст между ними и их коллегами, которые являются простыми исполнителями. Они делают других лучше. Делают отрасль чуть-чуть лучше. Это невозможно игнорировать.
Их отдача становится их секретным оружием. Когда они оказывают помощь, они доносят информацию другим о том, что:
Они эксперты.
Они знают, о чем они говорят.
Другие признают их компетентность.
Если разработчик Незаменимый, тогда он – звезда. Если вы именно такой, тогда ваша ценность стремительно растет.
А теперь лучшая часть – любой разработчик, каждый разработчик, может быть Незаменимым консультантом.
2. Не доверять своим клиентам, чтобы понять его потребности.
Я только что сказал, что доверять клиентам – это плохая идея. Теперь я говорю, что и не доверять им – это ошибка?
Дело в том, что все вопросы за пределами основной работы разработчика – бизнес в целом, продажи, стратегия, маркетинг – это сферы, в которых он должен полагаться на своего клиента (то есть вашего работодателя).
Есть 2 типа реакции разработчиков при возникновении таких вопросов.
Первый – это определенная степень апатии и равнодушия. Как только возникает незнакомая тема, такие разработчики тушуются или отключаются. Такое отношение говорит прямо: мне все равно.
Второй – это знатоки. Есть разработчики, которые «думают», что разбираются абсолютно во всех вопросах. Они не хотят учиться у тех, кого они считают «ниже» своего уровня, или же делают это неправильно.
Оба таких разработчика не понимают один важный нюанс.
Люди вокруг вас могут почувствовать такое отношение. Вместо ценного вклада они получают апатию или презрение. Они мысленно замечают это и в дальнейшем будут действовать соответственно.
Откуда я знаю, что я прав?
От вас. Вы принимаете к сведению такое же отношение и к себе. Сколько раз вы рекомендовали приятеля или друга для проекта? Сколько из ваших друзей устроились на работу по вашим рекомендациям или при вашей помощи? Как часто вы замечаете «того» сотрудника, который отказывается документировать свою работу? Понимаете, о чем я?
У вас есть стандарты. Как есть они и у других.
Разработчики «Рок-звезды» задают вопросы. Они проявляют инициативу. Они работают, чтобы понять, как могут помочь остальным (в управлении, финансах, маркетинге и т.д.). У таких разработчиков есть глубокое понимание того, как их работа затрагивает всех остальных.
Это редкое, но невероятно ценное качество.
3. Использование фразы «это невозможно сделать» как запасной вариант
Написание кода, по своей сути, является решением проблемы. Вы это уже знаете. Как и все остальные. Как разработчик, вы всегда спасаете ситуацию и превращаете идеи других в настоящую реальность. Разработчики - буквально инженеры будущего.
Поэтому, когда не-разработчик слышит фразу «это невозможно сделать», он не верит вам. Да и почему он должен поверить? Ведь снова и снова вы делали невозможное возможным. Раньше вы всегда находили способ выполнить работу. Вы обыскивали форумы, тестировали открытый исходный код, отправляли вопросы на Stack Overflow – вы делали все, что нужно было делать.
И пока вы не сдавались, вы побеждали.
Когда не-разработчик слышит «это невозможно сделать», то в действительности он слышит: «Я не хочу».
Ничто не раздражает так не-разработчика больше, чем слова: «это невозможно». Почему? Потому что это звучит так, будто Вы даже не хотите попробовать.
Поэтому сначала коллеги просят вас найти способ. Потому что они верят в вас. Конечно, иногда это раздражает. Это расстраивает, когда на вас бросают задачи и ожидают, что все будет сделано. Они думают, что все очень легко и просто.
Вы же знаете, что это не так. Ваши коллеги, как дети - они не знают, как это работает, просто вы волшебник, который делает зрелищные вещи. И они любят Вас за это.
Некоторые вещи действительно невозможны. Вся проблема в том, как сообщить о реальной невозможности. Вы обращаетесь к не-разработчику, гневаясь? Ворча и жалуясь за спиной? Распространяя плохое отношение вокруг?
Или, как разработчик, вы ищите компромисс? Вы предупреждаете их о негативных последствиях, которые связаны с тем, чего они хотят, и предлагаете решение?
4. Снисходительность и презрение
«Я ненавижу маркетинг».
«Менеджеры глупые».
«Продавцы хуже всех».
«Мой босс-идиот снова просит меня сделать что-то глупое».
Вы когда-нибудь думали подобным образом? Я знаю, что да, потому что я думал. Это совершенно естественно. На самом деле, многие люди так думают. Если Вы являетесь частью какой-то подгруппы, скорее всего, вы тоже так думаете.
В нашей культуре это даже поощряется.
Богатые против бедных
Разработчики vs маркетологи
Фриланс vs клиенты
Люди, с которыми мы взаимодействуем, не являются частью нашей группы разработчиков? Они чувствуют и знают, как мы на самом деле относимся к ним. Вот почему это проблема.
Вы и ваши коллеги должны быть в одной команде, только в этом случае не появляются «мы» и «они». Невидимые барьеры, которые делят вашу команду. Политика и борьба за влияние становятся нормой, поскольку каждый борется за свою работу. Бонусы, рост и стимулы начинают исчезать.
Отношение, от которого веет снисходительностью и презрением, делает две вещи.
Это отдаляет Вас от других людей. Вы становитесь «тем человеком», с которым ужасно работать.
Это медленно душит существующие отношения. Друзьям становится все труднее защищать вас, общение с вами начинает негативно сказываться на ваших коллегах. Они ничего не скажут напрямую – просто будут молча отдаляться.
Как только вы потеряете друзей и союзников, все начнет рушится, пока в конце концов вы не уйдете с работы.
5. Ложные обещания и незавершенная работа
«Я сделал».
«Получилось вроде неплохо».
Вероятно, вы и сами получали подобные обещания и ответы. Вы знаете, что «это сделано» может не отвечать действительности. Это распространенная ошибка.
Разработчик сообщает своему менеджеру, что команда закончила свою работу. "Все работает!" И менеджер делает то, что делают большинство хороших менеджеров. Он доверяет им и готовится проверить их работу.
Или, в некоторых случаях, он не выполняет проверку. Заведомо плохая идея, но он доверяет своим разработчикам. Он верит в них, поэтому рискует. Потому что его боссы дышат ему в затылок. Может быть, его работа на очереди или покупатель настаивает на доставке. Все, что угодно.
Как бы то ни было, вскоре менеджер обнаруживает, что разработчик, которому он доверял и на которого рассчитывал, подвел его.
Он никогда не забудет эту ошибку.
Ему будет трудно снова доверять этому разработчику. Это также может изменить его убеждения относительно разработчиков в целом. Несправедливо, конечно, но это реальность.
Если он умный, он проверяет и перепроверяет работу этого разработчика. Если он действительно умный, он проверяет работу каждого. Но это замедляет работу. Вместо того, чтобы доверять всем в команде, чтобы проявить себя и добиться своей цели, он попытается все проверить. Страх и неуверенность менеджера начинают расти.
До определенного дня… Когда вас посчитают ненадежным сотрудником.
Мы все сделали эти ошибки
И они еще не разрушили нашу карьеру. Хороший факт о людях: они дают второй шанс. И третий. И четвертый. Вы будете удивлены, сколько шансов вам готовы дать, когда вы компетентны и стараетесь быть лучше.
В какой-то момент люди теряют терпение. Они больше не хотят работать с теми, кто продолжает повторять свои ошибки, они не хотят мириться с этими проблемами. Когда так происходит, обычно виновных увольняют.
Повторите эти ошибки достаточное количество раз - и ваша карьера разработчика будет закончена. Ваш послужной список будет преследовать вас. Бывший коллега предупредит всех на новой работе, что от вас следует держаться подальше.
Великие разработчики не делают этих ошибок. Это правда.
Если Вы дочитали так далеко, есть большая вероятность, что вы один из них. Главная проблема – это ваше отношение, а не борьба со своими ошибками.
Если вы работаете над тем, чтобы стать лучше, вы добьетесь успеха. Если вы, узнав об этих ошибках, отреагировали негативно – в форме цинизма, горечи или обиды – тогда вы в зоне риска.
А как насчет других разработчиков? Тех, кто продолжает бороться с этими ошибками?
Будьте терпеливы с ними. Если они открыты к обсуждению, научите их. Поделитесь этой статьей. Помогите им стать лучше. Не оставляйте их одних. Получите помощь, если Вы сами боретесь с этими проблемами.
Потеря вашей карьеры – пугающая мысль
Представьте, что каждый день вы работаете и находитесь там, где необходимы. Где ваши коллеги доверяют вам. Где они видят в вас Незаменимую часть своей команды. Как бы вы себя чувствовали в таком окружении? Хорошо, правда? Вы получаете желаемые результаты от своей карьеры, вы - рок-звезда на работе, и вы контролируете свое профессиональное будущее.
Если вы действительно работаете. Навыки кодинга являются обязательными, но, как мы увидели, их недостаточно.
Станьте рок-звездой.
Введення в розробку програм під iOS. Частина 5
Автор: Volodymyr Bozhek
Здравствуйте, дорогие читатели.
В этом уроке мы научимся:
Добавлять иконку приложения;
Добавлять картинки в приложение. Разберем, как пользоваться “Assets”.
Откройте проект “Warehouse”.
В панели навигатора откройте модуль “Assets.xcassets”.
Нажмите “App Icon”, вы увидите область с контейнерами для добавления иконок приложения.
На рисунке выше нас интересуют два контейнера “iPhone App iOS 7-10 60pt”, тут задается иконка приложения.
В разделе “iPhone Notification iOS 7-10 20pt” задается иконка, которая будет отображаться при получении “Push” уведомлений от вашего приложения в заголовке сообщения.
В разделе “iPhone Spotlight – iOS 5,6 Settings – iOS 5-10 29 pt” задается иконка приложения, которая будет отображаться в диалоге поиска вашего телефона (если приложение под iOS 5 или 6) и в настройках телефона.
В разделе “iPhone Spotlight iOS 7-10 40pt” задается иконка, которая будет отображаться в диалоге поиска вашего телефона.
Теперь давайте разберем, что означают метки “2х” и “3х”. Метки- это размер иконок.
Например, ваша исходная иконка имеет размер “16х16”, для нее будет задана метка “1х”. Соответственно, для метки “2х” будет размер “32х32” (16+16 x 16+16), т.е. в два раза больше исходной иконки под меткой “1х”. Для метки “3х” будет размер “48х48” (16+16+16 x 16+16+16), т.е. в три раза больше исходной иконки под меткой “1х”.
Принято именовать иконки следующим образом:
Иконка с меткой 1х используется для iOS ниже 7 версии. Вам ее не нужно делать, так мы используем язык программирования “Swift” в нашем приложении и доступен он, только начиная с версии “iOS 8”, не ниже. В “iOS” ниже версии 8 доступен для использования язык программирования “Objective C”, его я не буду разбирать вообще, поскольку у него не удобочитаемый синтаксис и для новичков он будет сложным. Т.е., должно быть в таком формате “[Имя исходной иконки][Размер в “pt”][Метка].[Расширение файла иконки]”.
Таблица с размерами и метками иконок для раздела “iPhone Spotlight – iOS 5,6 Settings – iOS 5-10 29 pt”:
Таблица с размерами и метками иконок для раздела “iPhone Spotlight iOS 7-10 40pt”:
Таблица с размерами и метками иконок для раздела “iPhone App iOS 7-10 60pt” (иконка нашего приложения):
Таблица с размерами и метками иконок для раздела “iPhone Notification iOS 7-10 20pt”:
Итак, приступим к созданию нашей иконки. Скачайте файл “warehouse.png” (размер 512х512) ниже на странице себе на компьютер.
Откройте любой графический редактор, которым умеете пользоваться и создайте файлы иконок в соответствии с 4 разделами, приведенными выше в таблицах. Имена файлов должны соответствовать тем, что в 4 таблицах выше.
Как пользоваться графическим редактором, рассматривать не стану. Под OS X есть бесплатный графический редактор “Gimp”, есть платный “Adobe Photoshop”.
После обработки данного файла в графическом редакторе должны получиться на выходе следующие файлы:
Отлично с этим справились, теперь необходимо перетащить из “Finder” иконки “*.png” в соответствующие места в “App Icon” по разделам. Выполните это, должно получиться вот так:
Теперь закройте проект “Warehouse” и откройте его снова. Обратите внимание на иконку приложения, которая появилась в панели инструментов.
Запустите приложение. Затем выполните комбинацию клавиш “Shift + Command + H”, чтобы выйти на рабочий стол устройства. Обратите внимание на иконку приложения “Warehouse”, она тоже изменилась.
А вот так она выглядит в диалоге поиска “Spotlight”:
Теперь разберем, как добавлять картинки в ресурсы и отображать их в элементах управления. Тренироваться будет на списке товаров.
Прилагаю список картинок, которые мы будем использовать в ресурсах.
Скачайте эти картинки, затем выделите весь список. Откройте модуль “Assets.xcassets” и перетащите из “Finder” в пустую область под “App Icon” выделенный список загруженных картинок. Должно получиться вот так:
Все бы хорошо, если бы только не нововведения для картинок, начиная с iOS 10 и Xcode 8. До iOS 10, добавляя картинки подобным образом в ресурсы, все без проблем загружалось в AppStore. Но вот начиная с iOS 10, было принято, чтобы картинки были в двух разных форматах “sRGB” и “Display P3”, предпринято это было для возможности управления насыщенностью цветов. Более подробную информацию, как к этому пришли, можно получить, изучив “WWDC 16, Session 712, Working with Wide Color, Understanding and optimizing for Wide Color Gamut Displays”.
Если использовать версию среды разработки, например, Xcode 7.3.1, то в ней с минимальной версией приложения iOS 8.0 не надо делать никаких конвертаций с картинками, все без проблем загружается в AppStore. Если же загружать без конвертации “sRGB and Display P3” со среды разработки “Xcode 8”, то на этапе валидации мы получим ошибку “Invalid Bundle. The asset catalog at '$path' can't contain 16-bit or P3 assets if the app is targeting iOS releases earlier than iOS 9.3”.
Да, с одной стороны можно было поставить минимальную версию iOS 9.3, ничего не конвертировать и отправить приложение в AppStore, но тогда бы я потерял пользователей, у кого iOS 8, 8.1, 8.2, 8.3, 9, 9.1, 9.2, 9.2.1. Пришлось разбираться, как это исправить, чтобы выполнить загрузку в AppStore, и при этом минимальная версия так и осталась iOS 8.
Для конвертации изображений в OS X есть специальная бесплатная встроенная утилита “ColorSync Utility”. Картинки, которые я показывал выше, имеют формат “RGB”, чтобы убедиться в этом. В “Finder” выполните клик правой кнопкой мыши на картинке, например, “tool001.png” и в контекстном меню выберите пункт “Get info”.
Обратите внимание на свойство “Color space”, его значение “RGB”. Создайте где-нибудь две папки с названиями “Tools_sRGB” и “Tools_Display_P3”. В эти папки мы будем складывать сконвертированные картинки.
Картинка формата “Display P3” (16 битная) будет автоматически подгружаться, если у пользователя iOS 10, если же у пользователя версия операционной системы ниже iOS 10, будет браться картинка формата “sRGB” (8 битная).
Если вы добавите только картинки в формате “sRGB”, тогда, если у пользователя операционная система iOS 10, эти картинки будут каждый раз конвертироваться из формата “sRGB” в формат “Display P3”. Добавить только картинки формата “Display P3” и не добавить картинки формата “sRGB” нельзя, надо или в обоих форматах, или только в формате “sRGB”.
Если вы обратили внимание, когда добавляли картинки в “Assets.xcassets”, а затем выделили одну из добавленных картинок, с правой стороны от нее был отображен контейнер “Universal”. Давайте включим поддержку “Display Gamut”. Выделите “tool001.png”, в панели свойств откройте вкладку “Show the attributes inspector”. Найдите свойство “Gamut”, в нем сейчас установлено значение “Any”, установите значение “sRGB and Display P3”.
Перейдите в “Finder”, теперь мы должны сконвертировать исходные загруженные картинки в два формата “sRGB” и “Display P3”. Для этого в “Finder” выделите картинку “tool001.png”, выполните по ней клик правой кнопкой мыши и в контекстном меню выберите “ColorSync Utility.app”.
В открывшемся приложении “ColorSync utility”, внизу в выпадающем списке, измените значение “Match to Profile” на “Assign Profile”. Затем нажмите на выпадающий список “None” и выберите “Display”, затем “sRGB IEC61966-2.1”.
Кнопка “Apply” станет активной, нажмите на нее, затем закройте окно ColorSync “tool001.png”, нажав на красную кнопку в правом верхнем углу окна. Вам будет предложено сохранить изменения. Сохраните изменения.
Теперь перейдите в папку “Tools_sRGB”, которую мы создавали ранее, и выделите файл “tools001.png”, нажмите на нем правой кнопкой мыши и в контекстном меню выберите пункт “Get info”.
Обратите внимание на свойство “Color profile”, оно теперь имеет то значение “sRGB IEC61966-2.1”, которое мы устанавливали через утилиту “ColorSync”.
Теперь проделайте такую же операцию, еще раз с исходным файлом изображения “tool001.png”, но на этот раз выберите “Color profile” - “Display P3”.
Нажмите кнопку “Apply” и закройте окно ColorSync “tool001.png”, сохраните изменения в папку “Tools_Display_P3”. Затем откройте “Finder”, перейдите в папку “Tools_Display_P3”, выделите файл “tool001.png”, нажмите на нем правой кнопкой мыши и в контекстном меню выберите пункт “Get info”.
Обратите внимание на свойство “Color profile”, там установлено значение “Display P3”. Теперь перейдите в Xcode, откройте модуль “Assets.xcassets”, выделите изображение “tool001” и перенесите из “Finder” картинки в контейнер. В поле “1x sRGB” перетащите картинку “tool001.png” из папки “Tools_sRGB”. В поле “1x Display P3” перетащите картинку “tool001.png” из папки “Tools_Display_P3”. Должно получиться вот так:
Остальные картинки сконвертируйте самостоятельно в форматы “sRGB” и “Display P3” по той же схеме, что мы делали выше.
Ниже вы можете скачать две сконвертированные картинки.
Также добавим в “Assets” еще картинку фона страницы авторизации.
Она имеет размер “750х1334” и называется “warehouse-view.png”. Картинку тоже необходимо сконвертировать в два формата “sRGB” и “Display P3”.
В панели навигации откройте модуль “Main.storyboard”, найдите View с именем “View Controller”, из панели компонентов перетяните на View компонент “ImageView”.
Растяните его на всю область View. Нажмите кнопку “Pin” и задайте такие ограничения:
Нажмите кнопку “Add 4 Constraints”. Измените цвет кнопки “Вход” на оранжевый, цвет текста “Нет ошибок” на белый.
Откройте модуль “SuppliesViewController.swift”. Обновите модель “supplies”, как показано ниже (заполнены свойства “productImage”):
Обновите метод “cellForRowAt indexPath”:
Тут изменения только на 92 строке, в ячейке есть встроенный компонент “ImageView”, мы обращаемся к его экземпляру и от него инициализируем свойство “image”. В инициализаторe “UIImage” мы задаем аргумент “named”, название “Image Set” из “Assets”.
Запустите приложение.
На этом мы завершаем данный урок. Большой получился урок, но тему “Assets” надо было обязательно рассмотреть, чтобы в будущем к ней уже не возвращаться.
В следующем уроке мы рассмотрим, как работать с библиотекой “Alamofire” и интегрируем ее в наше приложение. Создадим тестовый сервер, в который добавим таблицу пользователей для авторизации, а в последующих уроках переведем работу списка продуктов на сервер и перепишем клиент на интеграцию с сервером.
Фундамент внутрішньої оптимізації. 5 залізних факторів
Автор: Андрій Афанасьєв
Введение
В начале данной статьи хочу поздравить Вас и себя со своей первой публикацией в 2016 году. Искренне желаю встречать на своем пути побольше ценной и интересной информации, а также людей, которые будут делиться бесценным опытом и помогут таким образом в Вашем профессиональном росте:)
А теперь можно приступить непосредственно и к теме данной публикации. Я не сомневаюсь, что многие уже успели перелопатить массу книг и статей о том, какой должна быть качественная внутренняя оптимизация, на что она влияет, какие тренды нас ждут в наступившем году, поскольку такой информации в Интернете целые массивы. Но меня это не остановило. Я уверен, что данный материал обязательно откроет что-то новое, позволит расставить акценты и сосредоточить внимание на самом главном. Тем более, кто дочитает эту статью до конца, получит небольшой, но приятный бонус:)
От слов к делу
Самый встречаемый вопрос, особенно среди новичков, звучит так: ”Внутренняя оптимизация - такой трудоемкий процесс, так много факторов и пунктов проверки. Подскажи, на что стоит обращать внимание в первую очередь?”. Отвечаю. Пожалуй, на всё. Наша жизнь состоит из мелочей и SEO-оптимизация тому не исключение. Практически невозможно сложить красивую картинку из пазла на 100 или даже 1000 элементов, если упустить часть деталей.
Поэтому остается только сосредоточиться, сесть за компьютер, поставить возле себя чашку ароматного кофе или чая, открывать чек-лист, кропотливо и внимательно анализировать проект по каждому из пунктов. В результате Вы получите полноценный труд в виде технического задания, которое, с большой вероятностью, Вам самим понравится и после внедрения обеспечит эффективное дальнейшее SEO-продвижение.
Но, несмотря на важность всех мелочей и нюансов, я подготовил материал, в котором выделю 5 моментов критической важности, то, без чего достигнуть крепких ТОПов и заполучить целевой трафик невозможно, с кратким комментарием по их решению. Плюс все будет лаконично и конструктивно, ведь вычитать «простынь» под силу не каждому :)
Наших 5 железных факторов
1. Семантика&Структура
Моментом №1 в SEO анализе и оптимизации является тот, насколько структура сайта позволяет его продвигать. Довольно часто возникает такая ситуация, что клиент хочет или требует оптимизацию сайта под семантику, к которой сайт совершенно не готов структурно. На сайте может не быть нужной вложенности, категорий и подкатегорий, страниц отзывов и прайсов, без которых эффективной оптимизации под интересную для клиента семантику не получится.
Поэтому, крайне важно параллельно выбирать и анализировать семантику, а также давать рекомендации и правки по структуре сайта. Семантика + структура - очень серьезная связка. Лучше согласовать и внедрить все моменты на берегу, чем когда Вы уже выйдете в открытое плаванье и придется грести веслами обратно. Но также важно помнить, что не любая семантика, которую предлагает или на которой настаивает клиент является правильной. В силу незнания он может быть убежден в одном, но в реальности дела могут обстоять иначе. Нивелируйте это своим погружением в бизнес и опытом.
2. Настройка карты сайта, ЧПУ и хлебных крошек.
Если на предыдущем этапе все ОК, двигаемся дальше. Думаю, каждому из нас хоть раз приходилось заблудиться на улице. В этом случае так хочется у первого встречного прохожого здесь и сейчас получить толковую консультацию, как попасть на улицу, которую мы ищем. А если мы еще и торопимся на жизненно важную встречу, то градус ситуации накален вдвойне. Шучу)
К чему все это? Правильная навигация важна и для поисковых роботов. Он не будет тратить время на то, чтобы сканировать страницы с непонятным назначением, уровнем вложенности и неизвестной глубины. Ему необходимо видеть эту структуру и навигацию. Поэтому на сайте обязательно должны быть настроены:
Человекопонятные url-адреса ЧПУ
Все url-адреса на сайте должны быть приведены к ЧПУ-виду и иметь вид http://url/. Кириллица должна трансформироваться в латиницу. В качестве разделителя слов в ЧПУ следует использовать дефис "-". Также будет неоспоримым плюсом, если в url-адресах будет соблюдаться полная вложенность, т.е. http://url/>/.
Пример не ЧПУ адреса может выглядеть так: site.domain/index.php?id=75. Примером ЧПУ адреса для этой же страницы может быть site.domain/itvdn.
После настройки ЧПУ следует также сделать 301 редирект с не-ЧПУ урлов на ЧПУ. В нашем случае это 301 редирект с site.domain/index.php?id=75 на site.domain/itvdn.
Настройка ЧПУшек и соответствующих редиректов, как правило, решается подключением стандартных плагинов. Если речь идет о самописной системе, скорее всего нужно будет «допиливать» соответствующий функционал.
Реализация «хлебных крошек» Breadcrumbs
Под «хлебными крошками» подразумевается навигационная цепочка, которая отражает вложенность структуры и чаще всего располагается над или под основным текстовым заголовком страницы.
Реализация Breadcrumbs полезна не только для того, чтобы показать поисковику глубину структуры сайта, но и с точки зрения юзабилити. Посетителю будет всегда удобно выйти на уровень или два уровня выше, допустим в каталог, если со страницей товара он полностью ознакомился, но хочет посмотреть что-то еще.
Карта сайта sitemap.xml
Как правило, данные карты генерируются стандартными плагинами в зависимости от того, на какой CMS сделан сайт. Либо есть универсальные решения, например, специальная CMS для генерации карт, которая интегрируется в корень сайта и парсит всю его структуру, в результате чего и генерируется карта сайта. Адрес, по которому должна быть доступна карта, желательно делать site.domain/sitemap.xml. Но и это еще не все. Необходимо после генерации карты скормить ее поисковому роботу в GWT в разделе «Файлы Sitemap».
Если с содержанием карты будет что-то не в порядке, Вы увидите соответствующие предупреждения об этом, которые потребуется исправить. Хочу еще подчеркнуть, что генерация карты сайта происходит в самом конце внедрения ТЗ оп оптимизации, когда устранены дубли, настроены правильные ЧПУ и т.д.
3. Диагностика и устранение дублей.
Дубли – это откровенное зло. Было бы Вам приятно, чтобы кто-то копировал Ваше поведение, одевался также, носил идентичную стрижку? Думаю, что вряд ли. И поисковые роботы в этом молодцы. Они такое рубят, занижают рейтинг целевых страниц и сайта в целом, если в его содержимом содержатся дубли. Каким образом их диагностировать? Для этого есть несколько методов. Самый простой - это воспользоваться данными по повторяющимся метатегам в разделе «Оптимизация HTML». Если дубли присутствуют, Вы увидите данные в таком виде:
Диагностировать дубли можно и с помощью программы NetpeakSpider. Такой вариант даже лучше в том плане, что он сканирует актуальную структуру сайта, а страницы в GWT сканируются периодически и информация может быть не первой свежести на момент, когда Вы ищите дубли.
Дальше сам собой напрашивается вопрос о том, как нам избавиться от них. Если дубль полный, т.е является 100% клоном страницы, которую дублирует, стоит проставить 301 редирект с дубля на основную страницу и отправить данный дубль на принудительную переиндексацию в разделе «Просмотреть как Googlebot».
Существуют и другие методы борьбы с полными дубликатами, например, закрытие их в robots.txt и принудительное удаление через GWT. Но 301 редиректы считаются наиболее эффективным и правильным методом.
В случае частичных дублей, например, когда дублируется только
и/или
и/или заголовки
необходимо переписывать метатеги на дублях вручную, если их много, либо формировать и внедрять шаблоны метатегов, которые в результате генерации будут уникальными для каждой страницы. Пример шаблона автогенерации метатегов может выглядеть, например, так:
После активной борьбы по искоренению дублей Вы в идеале сорвете джек-пот в таком виде:
Резюмируя данный пункт, предлагаю раз и навсегда сказать «Нет!» дублям, вовремя проверять их и давать отпор! Едем дальше…
4. Борьба с аффилиатами
Под аффилиатами подразумевается другой сайт клиента с такими же контактными данными, названием компании, структурой и тематикой. Поисковые системы “за естественную конкуренцию” и ведут борьбу с монополизацией рынка. Поэтому, склеивают аффилиаты, накладывая фильтры и занижая рейтинг сразу всех сайтов.
По статистике 2 из 3 клиентов приходят к нам с аффилиатами. В их качестве зачастую выступают не самостоятельные сайты на отдельных CMS и доменах, а площадки, сгенерированные на платформах типа Prom.ua или Allbiz.
Это плохая практика и что в таком случае требуется делать? Алгоритм простой:
Аргументируем клиенту всю ситуацию, запрашиваем доступы к аффилиатам, проверяем их.
Добавляем каждый аффилиат в Google Webmaster Tools.
Настраиваем 301 редиректы со всех страниц аффилиатов на главную страницу основного сайта.
Отправляем на принудительную переиндексацию аффилиаты.
Если нет возможности проставить 301 редирект, нужно воспользоваться опцией в GWT в разделе «Удалить URL-адреса».
Если внутри платформы нет возможности добавить сайт в панель вебмастеров (а такое случается часто), нужно просто согласовывать полное удаление сайта-аффилиата и ждать, когда он выпадет из индекса.
Такой простой алгоритм действий позволил нам вывести не один сайт из-под фильтра. Вот один из кейсов нашей компании, где мы непосредственно применяли данную методику и вытащили сайт с самого дна поиска на первые позиции.
Также бытует мнение, что достаточно изменить название компании, контактную информацию - и ситуация может измениться. Этот метод не работает. Не тратьте даже время на покупку новых телефонов и не ломайте голову, как бы себя по-новому еще назвать.
5. On-Page оптимизация
Подразумевает заточку и оптимизацию конкретных целевых страниц под семантическое ядро. Здесь важны следующие моменты:
Написание и размещение оптимизированных метатегов.
Подготовка и размещение полезного структурированного качественного текстового контента, при этом оптимизированного под нужные поисковые запросы.
Помимо контента текстового следует использовать качественные (желательно “не тяжелые” по объему памяти) изображения на всю ширину страницы. Это еще в тренде. Не помешают также тематические видеоролики, которые точно повлияют на поведенческие факторы ПФ (снизят показатели отказов и увеличат время нахождения пользователя на странице).
И многие другие интересные вещи, которые Вы узнаете дальше.
На десерт
Как я и обещал в начале данной статьи, Вас ожидает сюрприз. Под этой статьей находится pdf-файл «Полный чек-лист seo-оптимизатора от Abweb».
Запомните, что только титаническая работа позволит получить что-то стоящее не только в сфере SEO. Жду Ваших комментариев, до следующих публикаций!
Полный чек-лист seo-оптимизатора от Abweb
Запуск ASP.NET 5 на Linux
Автор: Редакция ITVDN
Введение
Данная статья содержит подсказки и советы, как правильно запустить ASP.NET vNext на Linux.
Если Вы используете метод чистой установки, вам следует установить Mono 3.4.1 или более позднюю версию. Вы можете сделать это путем составления источников. Также установка Mono возможна с помощью менеджера пакетов.
1. Доступ к Ubuntu с помощью удаленного рабочего стола
Если Ubuntu работает на облаке Windows Azure, а показать его нужно на Surface RТ, необходимо получить доступ к Ubuntu с помощью удалённого рабочего стола. Вот замечательное руководство по работе с удалённым рабочим столом с Ubuntu:
Как установить xrdp в Ubuntu 14.04
Если Вам не нужно запускать браузер, то удалённый рабочий стол Вам не понадобится. Чтобы увидеть веб-приложения, работающие на Linux, Вам нужно открыть некоторые порты или использовать туннель для Linux.
2. Установка K Runtime
Выполните следующие команды в терминале:
curl https://raw.githubusercontent.com/aspnet/Home/master/kvminstall.sh | sh && source ~/.kre/kvm/kvm.sh
Это позволит установить K Runtime Manager (KVM), K Runtime (Kre) и K Package Manager (KPM), также следует запустить приложения ASP.NET vNext.
3. Установите последнею версию KRE
Теперь давайте установим последнею версию KRE. Выполните такую команду в терминале:
kvm upgrade
Эта команда вызывает KVM для загрузки и установки последней версии KRE.
4. Натройка NuGet.config
Вполне возможно, что NuGet не имеет никакого представления об источнике пакета ASP.NET vNext. Вы можете найти NuGet.config в:
/home//.config/NuGet
Если он имеет только пустые и закрытые теги конфигурации, то для изменения содержимого выполняйте:
xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="AspNetVNext" value=https://www.myget.org/F/aspnetmaster/ />
<add key="NuGet.org" value="https://nuget.org/api/v2/" />
packageSources>
configuration>
5. Получите Ваше приложение из Git
Затем нужно получить источник ASP.NET vNext приложения для Вашей машины. Возможно, Вы используете Git. Чтобы скачать примеры приложений ASP.NET vNext, Вам нужно выполнить команду:
git clone https://github.com/aspnet/Home.git
6. Восстановление пакетов
Отправляйтесь к корневой папке вашего приложения ASP.NET vNext и, чтобы восстановить пакеты, используйте для запуска:
kpm restore
Теперь KPM восстанавливает все пакеты, необходимые для запуска приложения. Эта информация считывается из project.json файлов в приложениях корневых папок.
7. Запустите приложение
Пришло время для запуска приложения:
k kestrel
Эта команда вызывает KRE и использует Kestrel как веб-сервер.
Источник: http://gunnarpeipman.com/2014/10/running-asp-net-5-on-linux/