Как стать автором
Обновить
22
0.4
Алексей @pankraty

Разработчик

Отправить сообщение

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

Или, скажем, судебный процесс. Ваше ПО нарушает права человека, поэтому… Тадам! Вы не имеете права использовать библиотеку YYY, и обязаны удалить все ссылки на нее из источников.
А не "прекратить нарушать права человека, определенные в Конвенции… ", как некоторые могли по наивности подумать.

Я вот так и представляю диалог:


  • Шеф, есть библиотека ХХХ, которая как раз решает нашу проблему YYY. Может, заюзаем ее?
  • Нет, она выпущена под лицензией Гиппократа, а мы тут права человека собираемся нарушать, так что нет, сорян, нельзя.

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


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


Решение:


public class ExternalClassA
{
  // lots of properties
  public string PropertyA {get; }
  public int PropertyB { get; }
  // lots of other properties
}

public class ExternalClassB
{
  // lots of properties
  public string PropertyA {get; }
  public int PropertyB { get; }
  // lots of other properties
}

public class OurClass
{
  public void DoSomeWork(ExternalClassA subject)
  {
     DoSomeWorkInternal((dynamic) subject);
  }

  public void DoSomeWork(ExternalClassB subject)
  {
     DoSomeWorkInternal((dynamic) subject);
  }

  private void DoSomeWorkInternal(dynamic subject)
  {
     // here we can safely operate with subject.PropertyA, subject.PropertyB
  }
}

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

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

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

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


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

Да нет, я прекрасно понимаю, почему их нет. Просто неоднократно сталкивался с тем, что их наличие теоретически могло бы сделать запрос намного проще/нагляднее/понятнее.
Про отсутствие STRING_AGG до версии 2017 и связанные с этим костыли даже упоминать не хочется...

Это оконные функции, а речь про агрегатные. Они немного по-разному работают и не всегда взаимозамеяемы.

VIEW простая, в ней "всего лишь" фильтрация по результату оконной функции.


Что-то вроде


select * from (
  select id, status, date, rank() over (partition by id order by date desc) r
  from raw_statuses
) t
where r = 1

Как же не хватает агрегатных функций типа FIRST и LAST. Все способы обойти это выглядят костылями в той или иной степени...

О да, с "проталкиванием" параметров во VIEW буквально на днях столкнулся в полный рост.


Есть, скажем, таблица с историей статусов, и на ее основе создана VIEW, показывающая последний статус для каждой сущности. И если запрашивать данные по ID, план получается хороший, с index scan, запрос быстрый:


select v.last_status from status_view v where v.id = 123

Но если это же условие применяется в join-е, и даже если запись, к которой происходит join, будет строго одна в силу других условий, планировщик не парится, и делает full table scan, по всем миллионам записей:


select v.status 
from entity e
inner join status_view v on v.id = e.id
where e.number = 'xxx'

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

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


По-моему, тут явно удивление тому, зачем передавать треки, а не зачем передавать «с» и «по».

Касаемо удаления треков из плейлиста. Представим, что реализовано через указание ID плейлиста и номеров С и По. А дальше смоделируем следующие ситуации:


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

Так что существующее решение родилось не пустом месте и не ради усложнения жизни разработчикам.

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

Выбирать место наибольшего скопления котиков по наименьшему треугольнику — неправильно. Представьте пустую поляну, где в одном краю 100 котиков на расстоянии, в среднем, 30 см между каждой парой, а в другом — в коробке 20*20 три котенка. Ваша мята достанется котятам.


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

ОК, переименуем мы a и b в firstEdge и secondEdge. Splice — в AttachTwoEdgesTogetherOrBreakThemApart. Можем даже разбить на несколько методов. Только я сомневаюсь, что станет сильно понятнее.

А можно в комментарии дать ссылку на оригинал публикации, в которой не только разъясняются, для чего нужен QuadEgde, и что такое Splice, но и математически доказывается корректность алгоритма. И тому, кто будет разбираться с кодом намного удобнее будет видеть a, b, alpha, beta, Splice, Rot (1-в-1 соответствующие примерам в статье), а не наши искуственно выделенные функции и переименованные аргументы.
То есть, по вашему, краткий и лаконичный комментарий может быть длиннее по количеству символов чем непосредственная реализация?


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

public static void Splice(QuadEdge a, QuadEdge b)
{
	var alpha = a.ONext.Rot;
	var beta = b.ONext.Rot;

	var t1 = b.ONext;
	var t2 = a.ONext;
	var t3 = beta.ONext;
	var t4 = alpha.ONext;

	a.SetNext(t1);
	b.SetNext(t2);
	alpha.SetNext(t3);
	beta.SetNext(t4);
}

// Due to bug in version 2.5.345 we have to explicitly add [something] so that clients using that version would not crash


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

Вот статья, из которой я узнал про это https://m.habr.com/en/post/440576/
Отложилось в памяти, что это какая-то новая возможность, но не запомнил, это уже в релизе или в планах.
По работе с постгресом уже несколько лет не взаимодействовал, да и до этого не скажу чтобы прям глубоко погружался, так что многих тонкостей не знаю.

Возможно, вы путаете Postgres с MS SQL. В последнем действительно CTE — это поздзапрос, записанный в другой форме, а в Postgres оно материализуется (вроде бы в какой-то из последних версий добавили возможность не материализовывать CTE с помощью опции).


Что касается довода "SQL декларативный язык. То, что господин Manish с помощью переписывания текста запроса в другом формате получил более быстрое выполнение, это означает либо проблемы оптимизатора запросов у PostgreSQL..." — это так не работает. Да, оптимизатор не всесилен, и если переписывание запроса помогает ускорить его в десятки раз — надо переписывать. Ну или ждать, когда вендор научит СУБД правильно оптимизировать такой вариант запроса.

Информация

В рейтинге
1 988-й
Откуда
Саратов, Саратовская обл., Россия
Дата рождения
Зарегистрирован
Активность