Память точно не развивают. Проводилось исследование, в котором шахматистам разных уровней предлагали запомнить расположение фигур на доске. Если расположение фигур соответствовало какому-нибудь шахматному паттерну, профессионалы запоминали отлично, а новички — плохо. Если же расположение фигур было случайным, все уровни запоминали его одинаково плохо.
Тема развития определенных навыков и влияние этих навыков на все остальные аспекты жизни хорошо раскрыта в книге "Peak: Secrets from the New Science of Expertise". Автор книги является также автором исследования про 10000 часов, и в этой книге он объясняет, что популярная трактовка "10000 часов практики == профессионал" является неверной.
Как только число 3 превращают в объект, к нему гвоздями прибивают какой-то один смысл
…
оно ограничивает наши возможности по интерпретированию числа 3 каким-то иным образом
Вам ничего не мешает добавлять любой смысл к объекту. Если в вашей ментальной модели число может быть кодом символа, отобразите это в числе:
Это и отличает данные от объектов: у объекта есть «смысл»/интерпретация, пользуясь Вашей терминологией, а у данных этого нет.
…
Пока это число 3, это просто данные, и мы можем наделять их любым смыслом
То есть данные — это все-таки что-то, что не имеет никакого смысла? Если число «3» и строка «лето» являются данными, значит ли это, что они по-сути равны как друг другу, так и абстрактному «ничего»?
Конечно у числа есть собственный смысл, я это не отрицал. Я пытался донести идею о том, что числа — это не «данные», числа — это представление определенного смысла. А компактное представление смысла с возможностью исследовать и понимать смысл через использование доступных методов (операций, возможностей) — это объект.
Предлагаю отвлечься от программирования и подумать о том, как объяснить смысл чисел, например, дельфину.
Ребенку, который не знает чисел и основ математики, будет непонятно число 3. Для такого ребенка в числе 3 нет смысла. Он не сможет интерпретировать сообщение «3 + 2», потому что не знает смысл объектов «3» и «2» и доступных у них методов вроде "+" и "-".
Хоть вы и не ответили на мои вопросы из прошлого сообщения, я все рано задам еще. Вы действительно думаете, что числа — это что-то не имеющее смысла? А если смысл всё-таки есть, то разве методы (операции, возможности) вроде "+", "-", "*", "/" существуют не для пояснения смысла, заключенного в число?
число 3 это не объект, равно как и функция sum(a,b int) не является частью/методом какого-то объекта.
А что такое число 3? Это «данные»? А что такое «данные»? Как «данные» могут существовать без интерпретатора?
Если я напишу вам сообщение «На столе три яблока», или «На столе 3 яблока», или «На столе III яблока», скорее всего, во всех трех случая вы представите себе подобное:
У этих сообщений один смысл, и наши интерпретаторы позволяют понять смысл каждого из этих сообщений, потому что мы знаем русский язык, арабские и римские цифры.
Объект — упаковка для смысла. Методы объекта — способ понимания смысла.
"Код на Smalltalk"
tableWithThreeApples := me interpret: 'На столе три яблока'
apple := tableWithThreeApples takeOneApple.
apple isFruit. "true"
numberOfApples := tableWithThreeApple howManyApplesDoYouHave.
numberOfApples = 2. "true"
Но если интерпретаторы разные, то и объекты, а значит и смысл могут быть разными. Вполне возможен такой поворот событий:
tableWithThreeApples := appleFanboy interpret: 'На столе три яблока'
apple := tableWithThreeApples takeOneApple.
apple isFruit. "false"
apple isComputer. "true"
numberOfApples := tableWithThreeApple howManyApplesDoYouHave.
numberOfApples = 2. "true"
Возвращаясь к числу 3, невозможно понять его смысл, пока нет объекта, который этот смысл упаковывает, и методов, которые этот смысл поясняют.
Ваш первый пример ничем не отличается от объекта в ООП.
Микросервис, как и объект, инкапсулирует свое состояние и позволяет общаться с собой только при помощи посылки сообщений. Объект, как и микросервис, позволяет обрабатывать сообщение любым подходящим способом: хоть с помощью функционального подхода, хоть с помощью логического. И объект, и микросервис поддерживают динамический диспатч (полиморфизм):
В моём первом комментарии transform использовался вместо нового синтаксиса в list comprehension во всем проекте. То есть предполагалось переиспользование этой функции, а значит нужно либо вводить новую абстракцию, либо везде использовать последний вариант:
result = list(filter(filter_func, map(long_running_func, data)))
Я согласен, что абстракция не нужна, если проблема, которую решает эта абстракция, не сильно распространена в коде. Просто я исходил из предположения, что проблема сильно распространена.
Жаль, в python у коллекций нет методов map и filter, чтобы пример выше выглядел читабельнее:
result = data.map(long_running_func).filter(filter_func)
Адекватный разработчик узнает ограничения, в которых было написано это решение. Здесь transform решает проблему вызова долгой функции два раза. Если у адекватного разработчика будет более симпатичный вариант решения, то он его предложит, а не будет заворачивать ревью.
Почему бы не отрефакторить и сделать «Без», но линейно и прозрачно?
reductor = dispatch_table.get(cls)
if reductor:
return reductor(x)
reductor = getattr(x, "__reduce_ex__", None)
if reductor:
return reductor(4)
reductor = getattr(x, "__reduce__", None)
if reductor:
return reductor()
raise Error("un(shallow)copyable object of type %s" % cls)
Сразу видно повторение структуры
reductor = some_get_reductor_strategy()
if reductor:
return reductor(something_or_nothing)
Которую частично можно заменить nullable object'ом
def dummy_reductor(*args): pass
result = dispatch_table.get(cls, dummy_reductor)(x)
if result:
return result
result = getattr(x, "__reduce_ex__", dummy_reductor)(4)
if result:
return result
result = getattr(x, "__reduce__", dummy_reductor)()
if result:
return result
raise Error("un(shallow)copyable object of type %s" % cls)
И избавиться от повторяющихся if'ов
def dummy_reductor(*args): pass
result = (
dispatch_table.get(cls, dummy_reductor)(x) or
getattr(x, '__reduce_ex__', dummy_reductor)(4) or
getattr(x, '__reduce__', dummy_reductor)()
)
assert result, 'un(shallow)copyable object of type %s' % cls
return result
Уверен, что код можно еще упростить, если знать контекст.
В list comprehension новая фича выглядит полезной, пока не приходит осознание, что при реальной необходимости её можно реализовать самостоятельно один раз на весь проект:
def transform(iterable, with_transform, and_filter):
result = []
for item in iterable:
item = with_transform(item)
if and_filter(item):
result.append(item)
return result
result = transform(
data,
with_transform=long_running_func,
and_filter=lambda x: x is not None
)
result = transform(data, long_running_func, lambda x: x is not None)
Представьте, что вы воспользовались сервисом по уборке квартиры. Они пришли, начали уборку, но, по ходу дела, всю мебель в квартире переставили и шторы из гостинной в ванну перевесили с аргументацией "в таких условиях уборщице было приятнее выполнять свою работу". Картинку с "WTF?!" можете домыслить сами.
Для программиста код — это как раз та квартира, в которой он живет 5 дней в неделю по 8 часов. И жить в ней должно быть комфортно. Программист в данном случае — это не уборщица. Бизнесу же плевать на этот комфорт. В данном примере скорее бизнес — это уборщица, которая зачем-то запрещает мне переставлять мебель в моей же квартире.
И просто хорошая цитата про рефакторинг:
for each desired change, make the change easy (warning: this may be hard), then make the easy change
— Kent Beck (@KentBeck) 25 сентября 2012 г.
Когда мы размышляем об объектах, то первое, что приходит в голову — это классы.
Видимо, зря придумали ключевое слово class, оно затмевает сознание и мешает думать об объектах. В JS можно создавать объекты вообще без this, new и class, а только с помощью фабрик, замыканий и, собственно, объектов:
function Queue() {
const store = [];
return {
enqueue(elem) { store.unshift(elem); },
dequeue() { return store.pop(); },
}
}
Большие куски кода трудно тестировать. Большие методы, использующие кучу данных, практически нереально покрыть Unit тестами, а интеграционные тесты оказываются огромными и очень сложными.
Если код приходится "покрывать" тестами, лучше забыть про Unit-тесты, иначе и в тестировании разочаруетесь, и руководителям нервы испортите. Напишите интеграционные или приемочные тесты. Главное, чтобы они позволили без страха рефакторить и добавлять новый функционал. А новый код пишите по TDD.
Большие куски кода сложно ревьюить.
Ревью — вообще проблема и один из самых больших bottleneck'ов в процессе доставки продукта конечному пользователю. И на больших, и на маленьких кусках кода. Человек, который делает ревью, не может адекватно оценить решение, потому что он не в контексте задачи. Обычно на ревью находят всякую стилистическую шелуху, которую при наличии тестов можно поправить в любой момент.
Быть в контексте задачи помогает парное программирование, но продать его руководству очень сложно.
Переиспользуйте код, выделяйте абстракции, не стесняйтесь.
Пожалуйста, не выделяйте абстракции, когда пишите код. Они будут дерьмом, всегда. Решите сначала свою задачу, а в фазе рефакторинга, если код действительно будет "кричать" о необходимости абстракции, выделяйте.
Чтобы писать меньше кода, нужно:
перестать реализовывать бесполезные фичи
решать с помощью кода только текущие проблемы, а не мечтать "когда мы будем как Facebook, такое простое решение работать не будет"
сначала написать падающий тест
потом заставить тест проходить
закончить рефакторингом
если рефакторинг не идет — оставьте код в покое, позже все равно поймете как сделать лучше
Рассматривали ли вы вариант использования монорепозитория? Сразу уберет описанные вами боли, так как в dev-ветке модули, которые не изменялись, будут current-версии.
CI, Agile, DevOps имеют между собой одну общую черту — их убил маркетинг. Теперь CI — это не способ улучшения коммуникации в командах разработки, а GitlabCI, Jenkins, Travis и прочие инструменты. Agile и DevOps — не набор ценностей и принципов, а Kanban, Scrum, Daily meeting, Docker и другие buzzwords.
Очень похоже на религию, когда вместо философии и духа учения соблюдаются только обряды.
Память точно не развивают. Проводилось исследование, в котором шахматистам разных уровней предлагали запомнить расположение фигур на доске. Если расположение фигур соответствовало какому-нибудь шахматному паттерну, профессионалы запоминали отлично, а новички — плохо. Если же расположение фигур было случайным, все уровни запоминали его одинаково плохо.
Тема развития определенных навыков и влияние этих навыков на все остальные аспекты жизни хорошо раскрыта в книге "Peak: Secrets from the New Science of Expertise". Автор книги является также автором исследования про 10000 часов, и в этой книге он объясняет, что популярная трактовка "10000 часов практики == профессионал" является неверной.
Вам ничего не мешает добавлять любой смысл к объекту. Если в вашей ментальной модели число может быть кодом символа, отобразите это в числе:
То есть данные — это все-таки что-то, что не имеет никакого смысла? Если число «3» и строка «лето» являются данными, значит ли это, что они по-сути равны как друг другу, так и абстрактному «ничего»?
Как сделать так, чтобы можно было передать смысл одного и того же объекта без искажений?
Предлагаю отвлечься от программирования и подумать о том, как объяснить смысл чисел, например, дельфину.
Хоть вы и не ответили на мои вопросы из прошлого сообщения, я все рано задам еще. Вы действительно думаете, что числа — это что-то не имеющее смысла? А если смысл всё-таки есть, то разве методы (операции, возможности) вроде "+", "-", "*", "/" существуют не для пояснения смысла, заключенного в число?
А что такое число 3? Это «данные»? А что такое «данные»? Как «данные» могут существовать без интерпретатора?
Если я напишу вам сообщение «На столе три яблока», или «На столе 3 яблока», или «На столе III яблока», скорее всего, во всех трех случая вы представите себе подобное:
У этих сообщений один смысл, и наши интерпретаторы позволяют понять смысл каждого из этих сообщений, потому что мы знаем русский язык, арабские и римские цифры.
Объект — упаковка для смысла. Методы объекта — способ понимания смысла.
Но если интерпретаторы разные, то и объекты, а значит и смысл могут быть разными. Вполне возможен такой поворот событий:
Возвращаясь к числу 3, невозможно понять его смысл, пока нет объекта, который этот смысл упаковывает, и методов, которые этот смысл поясняют.
Микросервис, как и объект, инкапсулирует свое состояние и позволяет общаться с собой только при помощи посылки сообщений. Объект, как и микросервис, позволяет обрабатывать сообщение любым подходящим способом: хоть с помощью функционального подхода, хоть с помощью логического. И объект, и микросервис поддерживают динамический диспатч (полиморфизм):
Вот здесь хорошо описано различие: https://www.stefankrause.net/wp/?p=342
transform
использовался вместо нового синтаксиса в list comprehension во всем проекте. То есть предполагалось переиспользование этой функции, а значит нужно либо вводить новую абстракцию, либо везде использовать последний вариант:Я согласен, что абстракция не нужна, если проблема, которую решает эта абстракция, не сильно распространена в коде. Просто я исходил из предположения, что проблема сильно распространена.
Жаль, в python у коллекций нет методов map и filter, чтобы пример выше выглядел читабельнее:
Сразу видно повторение структуры
Которую частично можно заменить nullable object'ом
И избавиться от повторяющихся if'ов
Уверен, что код можно еще упростить, если знать контекст.
В list comprehension новая фича выглядит полезной, пока не приходит осознание, что при реальной необходимости её можно реализовать самостоятельно один раз на весь проект:
Для программиста код — это как раз та квартира, в которой он живет 5 дней в неделю по 8 часов. И жить в ней должно быть комфортно. Программист в данном случае — это не уборщица. Бизнесу же плевать на этот комфорт. В данном примере скорее бизнес — это уборщица, которая зачем-то запрещает мне переставлять мебель в моей же квартире.
И просто хорошая цитата про рефакторинг:
Вместо
Object.setPrototypeOf(self, q)
можно использоватьObject.assign({}, q, self)
.Вам действительно нужно наследование? Если без него действительно никак не обойтись, то можно реализовать вот так:
Из-за "мокнутых кусков" тестирование превращается в ад. В данном случае, если очень хочется, можно создать фэйковый Queue и использовать его в тестах:
Конкретно этот пример надуманный, но суть он показывает.
А зачем разрастаться, если объекты можно делать маленькими и разносить по разным файлам?
Напишите, мне будет интересно почитать.
Лично мне такой подход дает больше гибкости. А вот классы обычно подталкивают к мышлению в рамках классов, код из-за этого наоборот теряет в гибкости.
JS прекрасный ОО-язык, но его зачем-то превращают в еще одну Java, а рынок, к сожалению, этот тренд поддерживает.
Видимо, зря придумали ключевое слово
class
, оно затмевает сознание и мешает думать об объектах. В JS можно создавать объекты вообще безthis
,new
иclass
, а только с помощью фабрик, замыканий и, собственно, объектов:Чем такой способ создания объектов хуже классов?
Если код приходится "покрывать" тестами, лучше забыть про Unit-тесты, иначе и в тестировании разочаруетесь, и руководителям нервы испортите. Напишите интеграционные или приемочные тесты. Главное, чтобы они позволили без страха рефакторить и добавлять новый функционал. А новый код пишите по TDD.
Ревью — вообще проблема и один из самых больших bottleneck'ов в процессе доставки продукта конечному пользователю. И на больших, и на маленьких кусках кода. Человек, который делает ревью, не может адекватно оценить решение, потому что он не в контексте задачи. Обычно на ревью находят всякую стилистическую шелуху, которую при наличии тестов можно поправить в любой момент.
Быть в контексте задачи помогает парное программирование, но продать его руководству очень сложно.
Пожалуйста, не выделяйте абстракции, когда пишите код. Они будут дерьмом, всегда. Решите сначала свою задачу, а в фазе рефакторинга, если код действительно будет "кричать" о необходимости абстракции, выделяйте.
Чтобы писать меньше кода, нужно:
Рассматривали ли вы вариант использования монорепозитория? Сразу уберет описанные вами боли, так как в dev-ветке модули, которые не изменялись, будут current-версии.
CI, Agile, DevOps имеют между собой одну общую черту — их убил маркетинг. Теперь CI — это не способ улучшения коммуникации в командах разработки, а GitlabCI, Jenkins, Travis и прочие инструменты. Agile и DevOps — не набор ценностей и принципов, а Kanban, Scrum, Daily meeting, Docker и другие buzzwords.
Очень похоже на религию, когда вместо философии и духа учения соблюдаются только обряды.
Если хочется логировать глобально все события, то можно использовать spy, который идет вместе с Mobx.
А что не так с декораторами и console? :)