Рубрика: Обо всем

  • Adminer — Легкий способ заглянуть в БД

    Adminer — Легкий способ заглянуть в БД

    Продолжаю серию лайфхаков для разработки своих pet-проектов. Сегодня мы всего за 2 мегабайта заглянем внутрь базы данных на своем сервере.

    Для этого нам понадобится Adminer — легковесный интерфейс для просмотра своих таблиц. Больше подходит, конечно, для вашего dev/stage окружения, но можно и на проде, только учитывайте риски и не публикуйте порты наружу для коммерческого продукта.

    Все что нужно сделать — добавить в docker compose следующий код:

      # Adminer для управления базой данных (доступен только через внутреннюю сеть)
      adminer:
        image: adminer:latest
        depends_on:
          db:
            condition: service_healthy
        restart: unless-stopped
        environment:
          - ADMINER_DEFAULT_SERVER=db
        networks:
          - app_network
        # Не публикуем порты наружу для безопасности

    Дальше хитрый трюк, хотите открыть его в браузере у себя на компьютере? Запустите команду ssh туннеля для маппинга портов:

    ssh -L 8080:localhost:8080 user@remote_server_ip

    Это одна из тех команд, которые я хотел бы знать гораздо раньше в своей карьере. Теперь на локалхосте у вас удаленный сайт открывается, и доступен он только вам!

  • Сколько вебсокетов можно открыть на один чат сервер?

    Сколько вебсокетов можно открыть на один чат сервер?

    Количество WebSocket-соединений, которые можно открыть на одном чат-сервере, зависит от нескольких факторов, но теоретически это число может быть очень большим. Рассмотрим основные аспекты:

    Теоретический максимум

    Теоретически, максимальное количество WebSocket-соединений на одном сервере может достигать огромных значений. Каждое соединение уникально идентифицируется комбинацией IP-адреса клиента и порта источника. Это означает, что теоретический предел составляет около 2^48 (примерно 281 триллион) соединений на один порт сервера.

    Практические ограничения

    На практике количество соединений ограничивается несколькими факторами:

    1. Ресурсы сервера: Память, CPU и пропускная способность сети являются ключевыми ограничивающими факторами.
    2. Настройки операционной системы: Лимиты на количество открытых файловых дескрипторов и сетевых соединений могут ограничивать максимальное число WebSocket-соединений.
    3. Производительность сервера: С увеличением числа соединений может падать общая производительность системы.

    Реальные примеры

    • WhatsApp и Phoenix: Эти платформы достигли показателя в 2 миллиона одновременных WebSocket-подключений на одном сервере.
    • Эксперименты с Java: Исследователи смогли открыть более миллиона TCP-соединений на одном сервере, что применимо и к WebSocket.

    Оптимизация для большого количества соединений

    Для поддержки большого числа WebSocket-соединений рекомендуется:

    1. Использовать асинхронные библиотеки: Они значительно повышают производительность за счет одновременной обработки задач.
    2. Поддерживать многопоточность: Автоматическая или ручная настройка многопоточности помогает масштабировать производительность.
    3. Выбирать эффективные языки и фреймворки: NodeJS, Java и C# показали хорошие результаты в тестах производительности WebSocket-серверов.
    4. Оптимизировать настройки сервера: Увеличение лимитов на файловые дескрипторы и сетевые соединения в ОС может существенно повысить возможности сервера.
    5. Использовать балансировку нагрузки: Распределение соединений между несколькими серверами позволяет масштабировать систему горизонтально.

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

  • Памятка по системному дизайну

    Памятка по системному дизайну

    Выбор правильной архитектуры = Выбор правильных сражений + Управление компромиссами

    Перевод: https://gist.github.com/vasanthk/485d1c25737e8e72759f

    Основные шаги

    1. Уточнить и согласовать масштаб системы
    • Варианты использования (описание последовательностей событий, которые в совокупности приводят к полезному действию системы)
    • Кто будет использовать систему?
    • Как они будут ее использовать?
    1. Ограничения
    • В основном определите ограничения по обработке трафика и данных в масштабе.
    • Масштаб системы (запросы в секунду, типы запросов, объем записываемых данных в секунду, объем считываемых данных в секунду)
    • Особые системные требования, такие как многопоточность, ориентация на чтение или запись.
    1. Проектирование архитектуры высокого уровня (абстрактный дизайн)
    • Набросайте важные компоненты и связи между ними, не вдаваясь в детали.
    • Уровень сервиса приложений (обслуживает запросы)
    • Перечислите различные необходимые сервисы.
    • Уровень хранения данных
    • Например, масштабируемая система обычно включает веб-сервер (балансировщик нагрузки, load balancer), сервис (разделение сервисов, service partition), базу данных (кластер баз данных master/slave) и системы кэширования.
    1. Проектирование компонентов
    • Компоненты + конкретные API, необходимые для каждого из них.
    • Объектно-ориентированный дизайн для функциональности.
    • Сопоставление функций с модулями: один сценарий для одного модуля.
    • Рассмотрите отношения между модулями:
      • Некоторые функции должны иметь уникальный экземпляр (Одиночки, Singletons)
      • Основной объект может состоять из многих других объектов (композиция, composition)
      • Один объект является другим объектом (наследование, inheritance)
    • Проектирование схемы базы данных.
    1. Понимание узких мест
    • Возможно, вашей системе нужен балансировщик нагрузки и множество машин за ним для обработки пользовательских запросов.
    • Или, возможно, данных так много, что вам нужно распределить базу данных на несколько машин. Каковы некоторые недостатки, возникающие при этом?
    • Слишком ли медленная база данных и нуждается ли она в кэшировании в памяти?
    1. Масштабирование абстрактного дизайна
    • Вертикальное масштабирование (vertical scaling)
      • Масштабирование путем добавления большей мощности (CPU, RAM) к существующей машине.
    • Горизонтальное масштабирование (horizontal scaling)
      • Масштабирование путем добавления большего количества машин в пул ресурсов.

    Кэширование (Caching)

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

    • Кэширование приложений требует явной интеграции в код приложения. Обычно оно проверяет, есть ли значение в кэше; если нет, извлекает значение из базы данных.
    • Кэширование базы данных, как правило, «бесплатно». Когда вы включаете базу данных, вы получаете некоторый уровень настройки по умолчанию, который обеспечит определенную степень кэширования и производительности.
    • Кэши в памяти (in-memory caches) наиболее мощны с точки зрения чистой производительности. Это потому, что они хранят весь набор данных в памяти, а доступ к RAM на порядки быстрее, чем к диску. Например, Memcached или Redis.

    Примеры:

    • Предварительный расчет результатов (например, количество посещений с каждого реферального домена за предыдущий день)
    • Предварительное создание дорогостоящих индексов (например, предлагаемые истории на основе истории кликов пользователя)
    • Хранение копий часто запрашиваемых данных в более быстром бэкенде (например, Memcache вместо PostgreSQL)

    Балансировка нагрузки (Load balancing)

    Публичные серверы масштабируемого веб-сервиса скрыты за балансировщиком нагрузки. Этот балансировщик нагрузки равномерно распределяет нагрузку (запросы от ваших пользователей) на вашу группу/кластер серверов приложений.

    Типы:

    • Умный клиент (трудно сделать идеально)
    • Аппаратные балансировщики нагрузки (дорого, но надежно)
    • Программные балансировщики нагрузки (гибридные — подходят для большинства систем)

    Репликация базы данных (Database replication)

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

    Партиционирование базы данных (Database partitioning)

    Партиционирование реляционных данных обычно относится к разложению ваших таблиц либо по строкам (горизонтально), либо по столбцам (вертикально).

    Map-Reduce

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

    Добавление слоя map-reduce позволяет выполнять интенсивные операции с данными и/или обработкой за разумное время. Вы можете использовать его для расчета предлагаемых пользователей в социальном графе или для создания аналитических отчетов. Например, Hadoop, и, возможно, Hive или HBase.

    Платформенный слой (Сервисы) (Platform Layer (Services))

    Разделение платформы и веб-приложения позволяет масштабировать части независимо. Если вы добавляете новый API, вы можете добавить серверы платформы без добавления ненужной мощности для уровня веб-приложения.

    Добавление платформенного слоя может быть способом повторного использования вашей инфраструктуры для нескольких продуктов или интерфейсов (веб-приложение, API, приложение для iPhone и т.д.) без написания слишком большого количества избыточного шаблонного кода для работы с кэшами, базами данных и т.д.

    Ключевые темы для проектирования системы

    1. Параллелизм (Concurrency)
    • Понимаете ли вы потоки, взаимоблокировку и голодание? Знаете ли вы, как распараллеливать алгоритмы? Понимаете ли вы согласованность и когерентность?
    1. Сетевое взаимодействие (Networking)
    • Примерно понимаете ли вы IPC и TCP/IP? Знаете ли вы разницу между пропускной способностью и задержкой, и когда каждый фактор является релевантным?
    1. Абстракция (Abstraction)
    • Вы должны понимать системы, на которых вы строите. Знаете ли вы примерно, как работают ОС, файловая система и база данных? Знаете ли вы о различных уровнях кэширования в современной ОС?
    1. Производительность в реальном мире (Real-World Performance)
    • Вы должны быть знакомы со скоростью всего, что может делать ваш компьютер, включая относительную производительность RAM, диска, SSD и вашей сети.
    1. Оценка (Estimation)
    • Оценка, особенно в форме приблизительного расчета, важна, потому что она помогает вам сузить список возможных решений только до тех, которые осуществимы. Тогда вам нужно написать только несколько прототипов или микро-бенчмарков.
    1. Доступность и надежность (Availability & Reliability)
    • Думаете ли вы о том, как вещи могут выйти из строя, особенно в распределенной среде? Знаете ли вы, как проектировать систему для борьбы с сетевыми сбоями? Понимаете ли вы долговечность?

    Соображения по проектированию системы веб-приложений:

    1. Безопасность (CORS)
    2. Использование CDN
    • Сеть доставки контента (CDN) — это система распределенных серверов (сеть), которая доставляет веб-страницы и другой веб-контент пользователю на основе географического расположения пользователя, происхождения веб-страницы и сервера доставки контента.
    • Эта услуга эффективна для ускорения доставки контента веб-сайтов с высоким трафиком и веб-сайтов с глобальным охватом. Чем ближе сервер CDN географически к пользователю, тем быстрее контент будет доставлен пользователю.
    • CDN также обеспечивают защиту от больших всплесков трафика.
    1. Полнотекстовый поиск (Full Text Search)
    • Использование Sphinx/Lucene/Solr — которые достигают быстрых поисковых ответов, потому что вместо прямого поиска по тексту они ищут по индексу.
    1. Автономная поддержка/Прогрессивное улучшение
    • Service Workers
    • Web Workers
    1. Серверный рендеринг (Server Side rendering)
    2. Асинхронная загрузка активов (Lazy load items)
    3. Минимизация сетевых запросов (Http2 + bundling/sprites и т.д.)
    4. Продуктивность разработчиков/Инструментарий
    5. Доступность (Accessibility)
    6. Интернационализация
    7. Отзывчивый дизайн (Responsive design)
    8. Совместимость браузеров

    Рабочие компоненты архитектуры фронтенда

    1. Код
    • HTML5/WAI-ARIA
    • Стандарты и организация кода CSS/Sass
    • Объектно-ориентированный подход (как объекты разбиваются и собираются вместе)
    • JS фреймворки/организация/техники оптимизации производительности
    1. Доставка активов — Фронтенд операции
    2. Документация
    • Документы по внедрению
    • Руководство по стилю/Библиотека шаблонов
    • Диаграммы архитектуры (поток кода, цепочка инструментов)
    1. Тестирование
    • Тестирование производительности
    • Визуальная регрессия
    • Модульное тестирование
    • Сквозное тестирование
    1. Процесс
    • Git Workflow
    • Управление зависимостями (npm, Bundler, Bower)
    • Системы сборки (Grunt/Gulp)
    • Процесс развертывания
    • Непрерывная интеграция (Travis CI, Jenkins)

  • Вопросы для уточнения функциональных и нефункциональных требований

    Вопросы для уточнения функциональных и нефункциональных требований

    ЭтапВопросыПримеры ответов
    Уточнение требованийКакие основные функции должна выполнять система?Система должна позволять пользователям загружать видео, просматривать их и оставлять комментарии
    Сколько пользователей будет у системы?Ожидается около 10 миллионов активных пользователей в месяц
    Какой ожидается рост пользовательской базы?Прогнозируется рост на 20% ежегодно в течение следующих 3 лет
    Какие основные сценарии использования системы?Загрузка видео, просмотр видео, поиск видео, комментирование
    Определение масштабаКакой ожидаемый объем данных?Ожидается хранение около 500 ТБ видео и 50 ГБ метаданных
    Какое соотношение операций чтения к записи?Ожидается соотношение 100:1 чтения к записи
    Какая ожидаемая пиковая нагрузка на систему?До 100 000 запросов в секунду в пиковые часы
    Определение APIКакие основные API endpoints нужны?/upload, /view, /search, /comment
    Какие параметры будут у этих API?/view?video_id=123, /search?query=cats
    Проектирование данныхКакая структура данных подойдет для хранения видео?Объектное хранилище для видеофайлов, реляционная БД для метаданных
    Как организовать индексирование для быстрого поиска?Инвертированный индекс по ключевым словам и тегам видео
    МасштабированиеКак обеспечить высокую доступность системы?Репликация данных, распределение по нескольким дата-центрам
    Как оптимизировать доставку контента пользователям?Использование CDN для кэширования популярных видео
    Как масштабировать обработку загрузки видео?Асинхронная обработка через очереди сообщений
    Дополнительные вопросыКак обеспечить безопасность системы?Шифрование данных, аутентификация пользователей, ограничение доступа
    Как организовать мониторинг системы?Сбор метрик производительности, логирование ошибок, алерты

  • Фазы TOGAF 10

    Фазы TOGAF 10

    ФазаОсновные решенияКлючевые документы
    Предварительная фазаОпределение организационной модели, архитектурных принципов, инструментальных средствОрганизационная модель, каталог архитектурных принципов
    Фаза A: Видение архитектурыРазработка высокоуровневого видения возможностей и бизнес-ценностейДокумент видения архитектуры, план управления архитектурным проектом
    Фаза B: Бизнес-архитектураРазработка бизнес-архитектуры, поддерживающей видениеМодель бизнес-архитектуры, каталог бизнес-служб
    Фаза C: Архитектура информационных системРазработка архитектуры информационных систем (данных и приложений)Модели данных, архитектура приложений, каталог систем
    Фаза D: Технологическая архитектураРазработка технологической архитектурыТехнологическая архитектура, спецификации инфраструктуры
    Фаза E: Возможности и решенияОпределение разрыва между текущей и целевой архитектурами, идентификация проектовПлан миграции, анализ разрывов, план проектов
    Фаза F: Планирование переходаРазработка детального плана перехода от текущей к целевой архитектуреДетальный план перехода, график миграции
    Фаза G: Управление реализациейРазработка процессов управления и контроля переходаПлан реализации, отчеты о статусе проектов
    Фаза H: Управление архитектурными изменениямиУстановление процессов управления архитектурными изменениямиПроцедуры управления изменениями, реестр изменений

  • Django, Postgres, Nginx с помощью Docker-Compose

    Django, Postgres, Nginx с помощью Docker-Compose

    В настоящем руководстве описан механизм автоматического деплоя трех контейнеров на локальный сервер. Контейнер с django проектом будет раздавать логику с помощью Gunicorn, контейнер с nginx будет раздавать статику и осуществлять так называемую reverse-proxy на Gunicorn для логики, контейнер с базой данных Postgres будет работать с настройками по умолчанию.

    Важные аспекты деплоя

    1. Контейнеры зависимы друг от друга, сначала запускаем базу данных, затем приложение, последним — nginx
    2. При создании контейнеров с помощью docker-compose они автоматически объединяются в локальную сеть.
    3. Выход из этой сети будет один и только один — это открытый порт контейнера nginx,
    4. Остальные контейнеры не будут иметь связей с портами хостовой машины, что, в целом, не мешает им открывать порты внутри той самой локальной сети, созданной docker-compose. Делают они это неявно, и конкретные порты, как правило, можно найти в документации к используемому образу
    5. Стандартный порт, где доступна база данных — 5432
    6. Стандартный порт, где доступен Gunicorn — 8000

    Volumes — Тома

    Нам понадобится 4 тома для хранения следующей информации: база данных, статика, медиа файлы, конфигурация nginx. Объявим их сразу за версией docker-compose:

    version: '3.8'
    
    volumes:
      postgres_data:
      static:
      media:
      nginx_conf:

    Контейнер 1: База данных

    Если внимательно прочитать документацию образа Postgres на Docker Hub, то можно выяснить, что контейнер этот легко запустить без каких либо дополнительных инструкций, главное, чтобы в наших переменных окружения был закрытый список необходимых для деплоя значений. Здесь мы используем одну маленькую, но очень удобную хитрость: мы используем одинаковые переменные окружения для контейнера с базой данных и контейнера с приложением django, где описано подключение к базе данных. Вот список:

    DB_ENGINE=django.db.backends.postgresql # для Django
    DB_NAME=postgres # для Django и Postgres
    POSTGRES_USER=postgres # для Django и Postgres
    POSTGRES_PASSWORD=postgrespostgres # для Django и Postgres
    DB_HOST=db # для Django
    DB_PORT=5432 # для Django

    Таким образом, код для docker-compose получается следующим:

    services:
      db:
        image: postgres:12.4
        restart: always
        volumes:
          - postgres_data:/var/lib/postgresql/data/
        env_file:
          - ./.env

    Указан образ, стоит ли перезапускать, если произойдет ошибка или сервер перезагрузится, путь к файлу базы данных внутри контейнера (это значение тоже из документации), а также откуда брать переменные окружения (в одной директории с docker-compose.yaml должен лежать файл .env).

    Наш контейнер теперь доступен только внутри сети из трех контейнеров по адресу db:5432

    Контейнер 2: Django и Gunicorn

    Так как Django раздает сам себя только в режиме debug=True, нам понадобится что-то более профессиональное, пусть этим займется Gunicorn. По умолчанию он раздает логику приложения на порту 8000, и нас это вполне устраивает, никаких дополнительных настроек здесь не требуется. Наш контейнер должен собраться только после того, как будет готова база данных. Как правило, скачивание образа, на котором будет построен ваш контейнер, занимает время, и за это время база уже построится и будет готова принимать соединения. Но при повторном деплое может произойти так, что база поднимется чуть позже, чем мы заходим применить стандартные наши команды: применить миграции и собрать статику. Поэтому в целях предотвращения этого я добавил в файл entrypoint.sh (который выполняется каждый раз при старте контейнера) инструкцию «подождать 10 секунд». Вот как выглядит код:

      django:
        image: matakov/yamdb:latest
        depends_on:
          - db
        restart: always
        env_file:
          - ./.env
        volumes:
          - static:/code/static
          - media:/code/media
          - nginx_conf:/code/nginx/
        entrypoint: /code/entrypoint.sh

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

    1. Статику в директорию со статикой
    2. Медиа файлы в директорию с медиафайлами
    3. Конфигурация Nginx берется их папки nginx. Тут есть важный момент. Наш контейнер с приложением должен первым забрать конфигурацию из этой папки и положить в свежесозданный образ. Если первым это сделает контейнер с nginx, то он подключит в образ свой конфиг по умолчанию, и он перезатрет (на самом деле не так, но для целей понимания будем говорить так) конфигурацию в нашем контейнере с приложением.

    Последняя инструкция запускает специальный файл каждый раз, когда контейнер стартует. Подробнее о проблемах, которые могут возникнуть с entrypoint.sh.

    entrypoint.sh

    #!/bin/sh
    
    sleep 10
    
    python manage.py migrate
    python manage.py createcachetable
    python manage.py collectstatic  --noinput
    gunicorn api_yamdb.wsgi:application --bind 0.0.0.0:8000
    
    exec "$@"
    

    Файл, который отслеживает подключение к базе данных, как только оно появляется, дает 10 секунд на то, чтобы все необходимые технические операции были завершены, затем мигрирует, создает кэш, собирает статику и, наконец, запускает Gunicorn на 8000 порту контейнера.

    Наш контейнер теперь доступен только внутри сети из трех контейнеров по адресу django:8000

    nginx.conf

    Чтобы наш сервер знал, как и с чем ему работать — нужно задать для него конфигурацию. Общая схема такая: на наш сервер на порт 80 приходит запрос, мы его проксируем на 80 порт контейнера с ngnix, он смотрит, если запрос на статику и медиа — отдает сам, а если запрос на логику — переадресовывает на контейнер с приложением на порт 8000. Приступим:

    upstream djangodocker {
        server django:8000;
    }
    
    server {
    
        listen 80;
    
        location / {
            proxy_pass http://djangodocker;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $host;
            proxy_redirect off;
        }
        location /static/ {
            alias /code/static/;
        }
    
        location /media/ {
            alias /code/media/;
        }
    
    }

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

    Дальше стандартный раздел server:

    Слушаем 80 порт, если запрос пришел на главную страницу и все остальные, кроме статики и медиа, отправляем на наш контейнер django:8000, используя красивый upsteam-ярлык для этого djangodocker. Остальные строки просто передают также дальше и заголовки запросов.

    Обратите внимание на команды root- Это означает, что /static/ приклеится к пути /code/ и станет /code/static

    Команда alias в свою очередь указывает сразу на конечное расположение. Маленькая хитрость, лучше знать.

    Контейнер 3: Nginx

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

      nginx:
        image: nginx:1.19.0-alpine
        ports:
          - "80:80"
        volumes:
          - static:/code/static
          - media:/code/media
          - nginx_conf:/etc/nginx/conf.d/
        depends_on:
          - django
        restart: always

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

    Если у вас на сервере уже есть сайт?

    Вы не можете в таком случае поднять свою сеть контейнеров на 80 порту, ведь он уже занят. В таком случае можно указать связку 8080:80, тогда ваше приложение будет доступно по ip:8080 в интернете. Если же вы хотите, чтобы оба сайта работали одновременно и на разных доменах, прочитайте статью про настройку веб-сервера Caddy и обязательно про безопасность открываемых портов.

    Далее — Continues Integration

    Разворачиваем приложение с помощью GitHub Actions

  • Как быть стоиком?

    Как быть стоиком?

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

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

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

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

  • Карты. Деньги. Фитнес-клуб.

    Карты. Деньги. Фитнес-клуб.

    Так как я уже два с половиной года консультирую фитнес-клуб по всем экономическим и техническим вопросам, не обходит меня стороной и литература, посвященная этому. Решил уточниться по продажам, так как приходится внедрять различные решения, которые им помогают. И приятно удивлен тем, насколько, согласно Александру Шумилину и Татьяне Ивановой хорошо отстроена у нас как философия, так и техническая часть продаж.

    Читая книгу, вспомнил свой первый опыт фитнеса. Я был откровенно напуган возможностями клуба, и этот страх несколько лет удерживал меня от покупки клубной карты. А мне всего лишь нужен был либо ментор, либо развернутая карта клуба с подробным руководством.

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

    Вроде как очевидные вещи, но мало получить знание. Нужно его применить и получить умение. А потом применить еще сотню раз и получить опыт.

  • Ген директора. 17 правил позитивного менеджмента по-русски (Владимир Моженков)

    Ген директора. 17 правил позитивного менеджмента по-русски (Владимир Моженков)

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

    Ген директора — отличная книга. Я вынес оттуда несколько вроде бы как всегда очевидных мыслей, но почему-то пока не услышишь, что кто-то это использует — это остается всего лишь мыслью. А теперь буду внедрять в свою жизнь. Начну, пожалуй, с планирования, как бизнеса, так и собственной жизни. Нужно понимать к чему движешься.

    Отдельное спасибо Алексею Румянцеву, который порекомендовал эту книгу.

  • Первая фотография черной дыры

    Первая фотография черной дыры

    Решил нарушить долгое молчание в блоге ради одного из величайших событий в истории человечества. Мы построили телескоп размером с Землю, увидели то, о чем только догадывались, подтвердили теории многих великий ученых.

    10 апреля — великий день в истории человечества.

    А на промо картинке к записи вы можете увидеть сравнительные размеры, если наложить нашу солнечную систему на черную дыру.

    Источник: NSF