10 km по набережной Котора

С момента забега в Бечейе прошёл месяц. И вот только сейчас я пришел в себя. Проснулся и понял, что вот она, снова тяга к физическим нагрузкам. Без долгого настроя проснулся, оделся и вышел на пробежку. Организм немного закис, но в целом было легко и приятно.

20241014_084221_b25f41.webp

Плюсы пробежки вдоль залива: очень красиво. Минусы, пульс от такой красоты скачает. Только выравняешь, как тут же “ой, солнце на травку красиво падает”. И пульс снова уходит в гору 😀

Kotor, Montenegro

20241014_084247_fcc80b.webp
Kotor, Montenegro

Видел как растут плоды граната

JavaScript. Взаимодействие с сервером

Примечание: Это статья — конспект моей лекции. В ней описываются ключевые понятия.

Обновление: В примерах ниже обновились url, в результате запросы по http не работают. Поэтому я внес небольшие корректировки и при получении url картинок заменяю http на https. Работающий код можно посмотреть тут https://codepen.io/denisfl/pen/xxeQzpp.

Чтобы взаимодействовать с сервером (запрашивать или отправлять данные), нам нужны методы. Каждый запрос, который мы отправляем на сервер, включает в себя endpoint и тип отправляемого запроса. Endpoint — это, своего рода, шлюз между клиентом и сервером. В зависимости от валидности запроса сервер отправляет ответ. Если запрос успешен, сервер возвращает данные, например, в формате JSON. В случае ошибки, сервер возвращает сообщение об ошибки. Ответы сервера обычно сопровождаются кодами состояния (status codes), которые помогают понять, что сервер пытается сказать при получении запроса.

Например: 200–299 — успешный запрос, 400–499 — ошибка клиента, 500–599 — ошибка сервера. Вот тут можно посмотреть полный список кодов: HTTP response status codes.

20241014_084402_ae1e5a.webp

Методы для отправки HTTP-запросов

GET. С помощью него клиент запрашивает у сервера содержимое ресурса.

HEAD. Это метод для получения заголовков ресурса. Обычно применяется для получения метаданных и проверки менялся ли ресурс с момента последнего посещения и существует ли он.

POST. Через этот метод клиент может передать данные в теле сообщения. Это могут быть какие-то данные с заполненной формы. POST является неидемпотентным методом, то есть при его отправке результат может отличаться. Кроме того, ответы на него не будут кэшироваться.

OPTIONS. С помощью него можно запросить список методов, которые он или его ресурс поддерживает. Также OPTIONS можно использовать для того, чтобы «пропинговать» сервер — протестировать его работоспособность.

PUT. Метод создаёт новый ресурс или заменяет существующий данными, которые указаны в теле запроса.

PATCH. Работает таким же образом, как и PUT, только по отношению к части ресурса.

DELETE. Клиент сообщает о том, что хотел бы удалить некий ресурс.

TRACE. С помощью него можно проверить, изменяют ли промежуточные узлы в сети запрос клиента.

CONNECT. Запускает туннель между клиентом и сервером.

Как запросить данные

XMLHttpRequest. Это довольно старый метод, тем не менее он все еще используется.

const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data', true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
const data = JSON.parse(xhr.responseText);
console.log(data);
}
};
xhr.send();

Axios. Это клиент созданный на Промисах, был создан для удобства работы с HTTP-запросами.

axios.get('https://api.example.com/data')
.then(response => console.log(response.data))
.catch(error => console.error('Ошибка:', error));

Fetch API. Это функция JavaScript, которую можно использовать для отправки запроса на любой URL-адрес веб-API и получения ответа.

fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Ошибка:', error));

Fetch и Axios очень похожи по функциональности. Axios создавался в тот момент, когда Fetch API не поддерживалось в разных браузерах и нужно было обеспечить совместимость с Internet Explorer. Сейчас можно использовать и то и другое, в зависимости от того, с чем комфортнее работать.

Запросили, получили, показали

Обычно если мы что-то запросили с сервера через GET, мы хотим это показать. В самом простом случае, мы вставляем полученные данные в DOM. Тут мы не говорим о современных решениях для работы с Virtual DOM.

Возьмем данные с http://pets-v2.dev-apis.com/pets и отрендерим их на страницы.

20241014_084426_8b3254.webp

Для запроса используем fetch api:

async function fetchData() {
try {
const response = await fetch('http://pets-v2.dev-apis.com/pets');
if (!response.ok) {
throw new Error('Ошибка при загрузке данных');
}
const data = await response.json();
// Допустим, у вас есть элемент в DOM для вставки данных
const container = document.getElementById('pets-container');
// Очищаем контейнер перед вставкой новых данных
container.innerHTML = '';
// Вставляем данные в DOM
data.forEach(pet => {
const petElement = document.createElement('div');
petElement.textContent = `Имя: ${pet.name}, Вид: ${pet.animal}`;
container.appendChild(petElement);
});
} catch (error) {
console.error('Произошла ошибка:', error);
}
}
// Вызываем функцию для загрузки данных
fetchData();

И применим этот код к html:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pets Data</title>
<style>
.pet {
margin-bottom: 20px;
border: 1px solid #ccc;
padding: 10px;
}
.pet img {
max-width: 100%;
height: auto;
}
</style>
</head>
<body>
<div id="loading-message">Загрузка данных...</div>
<div id="pets-container"></div>
<script>
async function fetchData() {
const loadingMessage = document.getElementById('loading-message');
const container = document.getElementById('pets-container');
try {
const response = await fetch('http://pets-v2.dev-apis.com/pets');
if (!response.ok) {
throw new Error('Ошибка при загрузке данных');
}
const data = await response.json();
loadingMessage.style.display = 'none'; // Скрываем сообщение о загрузке
// Очищаем контейнер перед вставкой новых данных
container.innerHTML = '';
// Вставляем данные каждого питомца в DOM
data.forEach(pet => {
const petElement = document.createElement('div');
petElement.classList.add('pet');
// Вставляем изображения питомца
pet.images.forEach(imageUrl => {
const img = document.createElement('img');
img.src = imageUrl;
petElement.appendChild(img);
});
// Вставляем информацию о питомце
const info = document.createElement('div');
info.innerHTML = `
<p><strong>Имя:</strong> ${pet.name}</p>
<p><strong>Вид:</strong> ${pet.animal}</p>
<p><strong>Город:</strong> ${pet.city}</p>
<p><strong>Штат:</strong> ${pet.state}</p>
<p><strong>Описание:</strong> ${pet.description}</p>
<p><strong>Порода:</strong> ${pet.breed}</p>
`;
petElement.appendChild(info);
container.appendChild(petElement);
});
} catch (error) {
console.error('Произошла ошибка:', error);
loadingMessage.textContent = 'Ошибка загрузки данных';
}
}
// Вызываем функцию для загрузки данных
fetchData();
</script>
</body>
</html>

В JavaScript функции являются объектами, и они могут иметь доступ к своему лексическому окружению, включая переменные и другие функции, определенные в том же контексте. В нашем случае, функция fetchData – это асинхронная функция, которая создает свое собственное лексическое окружение, когда она вызывается. Это лексическое окружение включает в себя все переменные и функции, определенные внутри нее, а также доступ к внешнему контексту, где она была объявлена.

Внутри функции fetchData мы обращаемся к внешним переменным, таким как loadingMessage и container. Эти переменные были определены в том же контексте, где и функция fetchData, и, следовательно, они доступны ей как внешние переменные.

Функция fetchData использует доступ к DOM-элементам loadingMessage и container, чтобы изменять их содержимое и стили. Это возможно благодаря замыканию, которое сохраняет ссылку на лексическое окружение, в котором была определена функция fetchData.

Внутри цикла forEach создается замыкание для каждой итерации. Это происходит потому, что каждый раз, когда вызывается метод appendChild() или устанавливается свойство innerHTML, создается новая функция, которая сохраняет ссылку на лексическое окружение функции fetchData.

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

В примере нижу функция fetchData и все переменные, которые она использует, организованы внутри объекта fetchDataObject. Все внутренние переменные функции, такие как loadingMessage и container, теперь доступны через ключевое слово this. Таким образом, объект fetchDataObject является замыканием, которое сохраняет доступ к своему лексическому окружению, включая переменные и методы.

const fetchDataObject = {
loadingMessage: document.getElementById('loading-message'),
container: document.getElementById('pets-container'),
fetchData: async function() {
const _self = this; // Сохраняем ссылку на текущий объект в переменной _self
try {
const response = await fetch('http://pets-v2.dev-apis.com/pets');
if (!response.ok) {
throw new Error('Ошибка при загрузке данных');
}
const data = await response.json();
_self.loadingMessage.style.display = 'none'; // Используем _self для доступа к свойству loadingMessage
_self.container.innerHTML = ''; // Используем _self для доступа к свойству container
data.forEach(pet => {
const petElement = document.createElement('div');
petElement.classList.add('pet');
pet.images.forEach(imageUrl => {
const img = document.createElement('img');
img.src = imageUrl;
petElement.appendChild(img);
});
const info = document.createElement('div');
info.innerHTML = `
<p><strong>Имя:</strong> ${pet.name}</p>
<p><strong>Вид:</strong> ${pet.animal}</p>
<p><strong>Город:</strong> ${pet.city}</p>
<p><strong>Штат:</strong> ${pet.state}</p>
<p><strong>Описание:</strong> ${pet.description}</p>
<p><strong>Порода:</strong> ${pet.breed}</p>
`;
petElement.appendChild(info);
_self.container.appendChild(petElement);
});
} catch (error) {
console.error('Произошла ошибка:', error);
_self.loadingMessage.textContent = 'Ошибка загрузки данных'; // Используем _self для доступа к свойству loadingMessage
}
}
};
fetchDataObject.fetchData();
// Вызываем метод fetchData объекта fetchDataObject для загрузки данных
fetchDataObject.fetchData();

В примере с объектом fetchDataObject, мы используем this внутри объекта для доступа к его свойствам (this.loadingMessage, this.container) и методам. Здесь this указывает на сам объект fetchDataObject, поэтому мы можем обращаться к его свойствам и методам через this.

В то же время, в асинхронной функции fetchData, когда мы создаем переменные loadingMessage и container, мы получаем доступ к этим переменным, используя this, потому что в момент выполнения асинхронной функции контекст может измениться и this может потерять своё значение. Таким образом, мы сохраняем доступ к нужным нам переменным, используя их как свойства объекта this.

А теперь перепишем объект fetchDataObject, используя стрелочные функции.

const fetchDataObject = {
loadingMessage: document.getElementById('loading-message'),
container: document.getElementById('pets-container'),
fetchData: async () => {
const { loadingMessage, container } = fetchDataObject;
try {
const response = await fetch('http://pets-v2.dev-apis.com/pets');
if (!response.ok) {
throw new Error('Ошибка при загрузке данных');
}
const data = await response.json();
loadingMessage.style.display = 'none';
container.innerHTML = '';
data.forEach(pet => {
const petElement = document.createElement('div');
petElement.classList.add('pet');
pet.images.forEach(imageUrl => {
const img = document.createElement('img');
img.src = imageUrl;
petElement.appendChild(img);
});
const info = document.createElement('div');
info.innerHTML = `
<p><strong>Имя:</strong> ${pet.name}</p>
<p><strong>Вид:</strong> ${pet.animal}</p>
<p><strong>Город:</strong> ${pet.city}</p>
<p><strong>Штат:</strong> ${pet.state}</p>
<p><strong>Описание:</strong> ${pet.description}</p>
<p><strong>Порода:</strong> ${pet.breed}</p>
`;
petElement.appendChild(info);
container.appendChild(petElement);
});
} catch (error) {
console.error('Произошла ошибка:', error);
loadingMessage.textContent = 'Ошибка загрузки данных';
}
}
};
fetchDataObject.fetchData();

Теперь функция fetchData не создает собственный контекст this, а вместо этого использует контекст объекта fetchDataObject. Мы также использовали деструктуризацию объекта внутри функции для получения доступа к свойствам loadingMessage и container.

Zellij — обновленный tmux на расте

Нарисовано специально для runhub.today

20241014_084526_e96ffe.webp

Настройка WordPress + GraphQL + Next.js

Когда-то давно, примерно лет 12 назад, я много работал с WordPress. Хотя он всегда позиционировал себя CMS для блогов, многие делали на нем не только блоги, потому что WordPress предоставлял удобную админку. Темы и плагины писать тоже было удобно. Но с развитием фронтенда со всеми сборщиками, реактами и полной сепарацией от бэкенда, возникла проблема: темы WP всегда были неотделимы от него, а фронтенд становился сложнее. В результате верстать и писать логику на js стало неудобно.

Спустя много лет, я решил посмотреть как же развивается WordPress и с удивлением обнаружил, что он теперь у него есть api. Более того, теперь можно запрашивать данные не только через REST API, но из GraphQL.

Изменилось все, даже способ установки. Так, к примеру, для установки WordPress на локальной машине можно использовать Docker образ для WordPress. Появились решения вроде LocalWP, Kinsta позволяющие запускать WordPress на локальной машине в один клик.

И это очень здорово, потому что команда WordPress решила ту самую проблему разработки тем и адаптировала свою систему под современные задачи.

По url https://yourdomain/wp-json/ доступен список всех роутов.

20241014_084614_8395c6.webp

С помощью плагина WPGraphQL можно добавить поддержку GraphQL.

20241014_084634_6ccae6.webp

Ниже опишу пример создания блога на WordPress + Nextjs.

Установим wordpress. Я использовал LocalWP.

20241014_084653_019a22.webp

Выбираем Create a new site и прокликиваем опции, оставляя все настройки по умолчанию. В результате, работающий на локальной машине WordPress должен выглядеть вот так. Нам нужен адрес сайта: notes.local.

20241014_084711_89d968.webp

Если хотите использовать сразу production сервер, могу посоветовать railway.app. Для простого пет-проекта подойдет бесплатный тариф.

После развертывания проекта, нам потребуется url, по которому будет доступен WordPress. В моем случае это dailynotes.up.railway.app.

20241014_084734_dc26f7.webp

Этот адрес сайта потребуется нам для запросов. Его следует вынести в .env файл, а сам файл добавить в .gitignore, чтобы этот файл не попал на github. Одна из причин по которой так следует делать: чтобы разные настройки не перемешивались. Например, на локальной машине у вас может быть один адрес сайта, а на продакшене другой. Другая причина — в .env файлах можно хранить ключи доступа, которые не должны быть доступны публично.

Следующим шагом устанавливаем nextjs: npx create-next-app@latest.

В корневой директории проекта я сделал файл .env.local и добавил туда url сайта:

NEXT_PUBLIC_WORDPRESS_API_URL=https://dailynotes.up.railway.app

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

Для получения данных мы создадим в корневой файл ./helpers/api.js:

const API_URL = `${process.env.NEXT_PUBLIC_WORDPRESS_API_URL}/graphql
async function fetchAPI(query = '', { variables } = {}) {
const headers = { 'Content-Type': 'application/json' }
const res = await fetch(API_URL, {
headers,
method: 'POST',
body: JSON.stringify({
query,
variables,
}),
})
const json = await res.json()
if (json.errors) {
console.error(json.errors)
throw new Error('Failed to fetch API')
}
return json.data
}
export async function fetchNotes() {
const data = await fetchAPI(`
query FetchNotes {
posts(where: {status: PUBLISH}) {
nodes {
id
title
content
date
}
}
}
`)
return data?.posts
}

fetchAPI предназначена для выполнения асинхронных запросов к API с использованием метода POST. Она принимает два аргумента: query (по умолчанию пустая строка) и объект параметров с именем variables (по умолчанию пустой объект).

Для получения постов мы будем использовать fetchNotes(), которая в свою очередь будет использовать функцию fetchApi(). На странице ./page.js можно будет вызвать fetchNotes(), чтобы запросить данные:

import { fetchNotes } from '@/app/helpers/api'
export default async function Home() {
const notes = await fetchNotes()
return (
<section>
{notes.nodes.map((note) => {
return (
<article className="note" key={note.id}>
<h2>{note.title}</h2>
<div className="note-content" dangerouslySetInnerHTML={{ __html: note.content }}></div>
</article>
)
})}
</section>
)
}

Это очень базовый пример, его цель дать примерное представление как это работает. В будущем его можно усложнить, дополнив запрос другой информацией.

От умных часов к глупым. Apple Watch, старая советская Seconda и Casio G-Shock

Upd: пост был написан 09 января 2022.

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

Около двух лет я носил Apple Watch Series 3. Носил их и днём и ночью, делая перерывы лишь на подзарядку. Но спустя какое-то время мне надоело заряжать каждый день, получать на них уведомления (даже если отключить звук и вибрацию, остается видна красная точка-индикатор), ставить на них обновления их и думать, что вот вышли новые часы и вот мои S3 уже не так хороши.

20241014_084815_9ef304.webp
Apple Watch 3

В какой-то момент я просто снял Apple Watch и больше не надевал. Поначалу без часов было немного странно. Мне очень нравилось что:

— ничего не надо заряжать
— если оставить телефон в другой комнате, то ничто не может меня побеспокоить. И тут важен именно психологический момент: нужно осознано взять и оставить телефон далеко. Не перевести его в беззвучный, а именно где-то оставить, чтобы иногда не заглядывать в него «а вдруг что-то важное».

В то же время, часы были нужны. На руке ощущалась непривычная пустота.

20241014_084837_041184.webp
Часы Seconda

Однажды на Авито наткнулся на продажу старых советских часов Seconda. Это механические часы на калибре 2609. Очень милые и простые часы. Я носил их несколько месяцев, пока случайно не открутил с вала заводную головку. Заводить часы всё так же не составляло проблем. Проблема возникла при корректировке времени — ее невозможно было сделать (удобным способом). Особенность в том, что их суточная погрешность -20/+40 секунд. То есть раз в два-три дня приходилось изворачиваться, чтобы скорректировать время.

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

В какой-то момент я даже начал собирать коллекцию часов, которые мне нравятся, на Pinterest. В этой коллекции есть как доступные по цене модели, так и те, которые никак не вписываются в разумные траты. Все часы из этой коллекции выглядят красиво (для меня конечно же, коллекция-то моя 😀 ), но не все они функциональны. Это те самые часы, в которых можно пойти на встречу, в кафе или в гости. Они хорошо дополняют вечерний взрослый наряд. Но хотелось чего-то повседневного. Того, что можно носить не снимаю. Купаться, работать во дворе и не бояться сломать. К тому же они должны стоить не слишком дорого, чтобы в случае их поломки, не нужно было копить пару лет, а просто пойти и купить другие без ощутимого ущерба для бюджета.

20241014_084859_51a697.webp
Casio G-Shock GA-2110SU-3A

Размышляя о приоритете функциональности над эстетикой я пришел к Casio G-Shock. Моя модель GA-2110SU-3A, она показалась мне одной из самых простых и имеет небольшую толщину по сравнению с остальными версиями джишоков.

Сравнивая их с Apple Watch, хочу сказать, что несмотря на практически одинаковый вес (AW – 52.8гр, G-Shock – 51гр), они ощущаются легче. Возможно из-за вида ощущения пластика, но ощущаются легче. К каучуковому ремешку Джишоков после силиконового или текстильного ремешков AW пришлось привыкать. Он жестковат и хотелось бы его немного разносить, смягчить. Но спустя месяц носки, мне кажется, что это отличный ремешок. Часы на руке сидят немного свободно и мне это удобно.

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

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

Вот пример того, как светятся стрелки, если зайти в темноту из хорошо освещенной комнаты.

20241014_084933_aafa6a.webp
Casio G-Shock GA-2110SU-3A

20241014_084956_15aa04.webp
Casio G-Shock GA-2110SU-3A

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

Интересным открытием оказался таймер. На AW я почти не пользовался таймером. Нужен был таймер — ставил его на телефоне. Сейчас кастомные таймеры на телефоне не исчезли, однако на часах я использую таймер в 25 минут для помидорной технике. В этот момент можно отложить телефон подальше.

Радует, что эти часы абсолютно не зависят от телефона. Они самодостаточны. Это просто часы.

Краткий пересказ книги «Ловушки мышления» (Чип Хиз и Дэн Хиз)

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

— вы сталкиваетесь с необходимостью выбирать;
— вы анализируете варианты;
— вы делаете выбор;
— а затем вы с этим живете.

В книге четыре стадии процесса принятия решений обозначаются аббревиатурой WRAP (Widen, Reality-test, Attain distance, Prepare). В русском варианте это могло бы звучать так:

— Расширьте границы выбора;
— Проверьте в реальных условиях;
— Дистанцируйтесь;
— Приготовьтесь.

Вы сталкиваетесь с необходимостью выбирать

Узкие рамки

Мы мыслим в узких рамках, в результате упускаем другие варианты. Это сравнимо с узконаправленным светом прожектора, который освещает участок театральной сцены. Если поводить прожектором в стороны, нам откроются ранее скрытые уголки сцены. Когда мы стоим перед выбором, нам стоит рассмотреть ситуацию с разных сторон. Возможно мы что-то упускаем.

Пример: Хочу в кино и на вечеринку. Но надо выбрать что-то одно. Стоит ли мне идти на вечеринку или нет?

А почему бы не заглянуть на вечеринку совсем на чуть-чуть, а потом поехать в кино? Вариант «и то, и другое» мы почему-то отсеяли, сведя выбор к «или».

Фиктивные варианты

Вторая крайность — слишком много вариантов. Среди них могут быть «фиктивные», склоняющие вас к выбору, который выгоден не вам.

Заимствуйте опыт

Может пока вы ищите альтернативы, кто-то уже решил вашу проблему. Поищите того, у кого перенять передовой опыт.

Вы анализируете варианты

При анализе вариантов происходит сбор данных. Почему вариант А лучше Б?

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

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

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

Вместо того чтобы доверять экспертам, проверяйте на практике.

Вы делаете выбор

Выбирать нужно умом, а не сердцем. Эмоции провоцируют нас на неверный выбор.

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

А еще: «спешите купить, эта модель последняя». Мы не любим терять. Ощущение потери для нас болезненно и не компенсируется ощущением удовольствия от равнозначной выгоды.

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

Дистанцируйтесь

Попробуйте посмотреть на ситуацию из вне. Допустим, выбор нужно сделать не вам, а другу. Чтобы вы ему посоветовали в этом случае?

Можно дистанцироваться с помощью правила 10/10/10: станет ли для меня это важно через 10 минут/ 10 месяцев/ 10 лет?

Однако успокоение эмоций может не облегчить решение. Если разум говорит одно, а сердце другое, это означает конфликт приоритетов. Подумайте что вы хотите. Составьте список «прекратить делать», в котором опишите что отбросить, чтобы сосредоточиться на приоритетах. Заведите будильник, который будет периодически звонить, побуждая вас задать вопрос «а тем ли я занят?» Это поможет перестать двигаться на автопилоте и осознать выбор.

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

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

А затем вы с этим живете

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

А если сложится не так, как мы хотели? Будущее — не точка, это диапазон возможных событий. Поэтому возможна ошибка в предположениях и ожиданиях. При принятии решений необходимо рассматривать разные исходы событий. В том числе и плохие сценарии.

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

Пример: вы хотите повышения зарплаты. Вы решаете обсудить это с шефом. Что может произойти в результате вашего общения?

— вам повысят зарплату
— вы получите отказ
— повысят зарплату, но не настолько, насколько вы хотели

Когда вы готовитесь к разговору, прокрутите в голове альтернативные исходы разговора. Что делать в каждом из возможных исходов?

Вывод: принятие решения — процесс, который можно разложить на этапы: поиск вариантов, сбор данных, выбор… А потом вы с этим живете.

Настройка MacOS

Этот список переходит из блога в блог и играет роль хранилища ссылок. Программы устаревают, обновляются и все повторяется по кругу.

Самая полезная ссылка — Mac OS X Setup Guide.

В первую очередь

— Atom => VS Code, neovim
iTerm, Warp
— Wunderlist => Singularity

Мессенджеры

— Skype
— Slack
— Telegram

Браузеры

Firefox

Графические программы

— Adobe Photoshop => Pixelmator

Утилиты

Macs Fan Control
The Unarchiver
Transmission
Spotify
VLC Player
Xcode: xcode-select --install

Настройка системы

Mac OS X Setup Guide

Homebrew
ohmyz.sh + .zshrc config
— Git: brew install git
NodeJS