Обновить
-6
Валерий Лиховских@vl65

Программист, Архитектор, Руководитель проекта

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

Для сервера приложения - "по волшебству" запросто !!! Со стороны клиентской части - тоже можно обеспечить автоматическое "появление". Если Вы работаете с СУБД то такими программами Вы уже пользуетесь практически ежедневно, которым достаточно указать требуемую БД и можно манипулировать ее содержимым не используя SQL. Степень "автоматизации" и интерфейс пользователя у них разный. При желании, думаю, и Вы можете написать подобную программу, которая на основании метаданных БД будет генерировать какие то диалоговые окна со списками выбора и прочими плюшками пользовательского интерфейса.

Само название ORM Вам говорит, что модель данных соответствует модели объектов (программной модели), т.е. накладывает жесткая связь между этими программными слоями.

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

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

ORM по сути превращает два изолированных друг от друга макро слоя (слой хранения данных и программный слой приложения) в один. Изменения в модели данных требует обязательного изменения программной модели и наоборот. Результат - ужасно плохая модифицируемость приложения.

Мой взгляд на тему ...

ПО должно быть разбито на "кубики" (слои, если кому то этот термин больше нравиться). Каждый "кубик" должен иметь очень узкую функциональность и не лезть или дублировать функционал соседнего "кубика".
В качестве примера можно привести 7-и уровневую модель IP стека, где каждый уровень (кубик, слой) выполняет только свою определенную функцию.

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

Для разбиения кода на "кубики" требуется как правило 2 - 3 итерации. Первая итерация, по сути, это "проверка гипотезы" - лишь бы работало. Код здесь плохой, как правило на ней и останавливаются. Вторая итерация - это уже переосмысление кода первой итерации и биение его на кубики. Здесь уже можно получить конечный вариант. Но возможно потребуется и третья итерация переосмысления полученного результата второй итерации.

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

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

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

Мое решение примерно 2 раза быстрее вашего, как я и предполагал выше

Решил все же сравнить производительность двух подходов преобразования. Запустил в цикле (код выше и ниже) без вывода прямое и обратное преобразование

Предложенное мной решение работает быстрее примерно в 2 раза
63 мс - 1000 циклов, вариант предложенный мной
105 мс - 1000 циклов, вариант предложенный foal

Результат многократного запуска стабилен (хоть цифры и меняются)


	public static void main(String[] args) {
		long start = System.currentTimeMillis();
		Timestamp t = new Timestamp(System.currentTimeMillis());
		
		for (int index = 0; index < 1000; index++ ) {
			t.setNanos(345012000); // устанавливать наносекунды
			TimestampFormatter f = new TimestampFormatter();
			String s = f.format(t);
			try {
	            // обратное преобразование для проверки
				Timestamp n = f.parse(s);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		System.out.println(System.currentTimeMillis() - start);
		
		start = System.currentTimeMillis();
		
		for (int index = 0; index < 1000; index++ ) {
			t.setNanos(345012000);
			DateTimeFormatter f = DateTimeFormatter
	          .ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX")
	          .withZone(ZoneId.systemDefault());
			String s = f.format(t.toInstant());
			try {
				// обратное преобразование для проверки
				Timestamp n = Timestamp.from(f.parse(s, Instant::from));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		System.out.println(System.currentTimeMillis() - start);
	}


Хорошая точка зрения

Кроме как глупостью аргументировать свою позицию видать Вы не в состоянии.

А теперь можно перейти к предложенному вами решению.

На мой взгляд, пакет java.time очень узко специализированный и, как я понимаю, назначение у него совсем другое чем предложенное Вами решение. Предполагаю, что и в производительности ваше решение проиграет - логика классов более сложная, соответственно, и время на преобразование должно тратиться больше. Да и использовать классы из этого пакета только чтобы получить микро/нано секунды у класса Timestamp, на мой взгляд, как то не оправдано. Избавит ваше решение от использования "устаревшего" класса SimpleDateFormat? Нет! Этот класс используется во многих библиотеках. Поведение этого класса предсказуемо в разных реализациях JVM и разных производителей, "сюрпризов" не ожидается. А то что одни и те же "базовые" класса JVM ведут себя по разному в реализациях JVM разных производителей это факт, что может если и не нарушать работу вашего кода, то сказываться на его логике.

Знаете выражение, "Не судите и не судимы будете", Не я Вас начал учить, но раз Вы начали, почему бы мне заняться тем же самым в отношении Вас.

Значит не справились с домашним заданием. Хотя попробовали мыслить в нужном направлении. Хвалю, но ответ не верный. Значит не гуру!

Ответ на поверхности. Где используется класс Timestamp? В JDBC. Нужно преобразование, которое выполняется в этом классе в связке приложение - база? Нет!. В этой связке все прекрасно работает и без этого преобразования. А где нужно? В REST, SOAP и прочих подобных протоколах. И действительно, при значении null, дело не дойдет до вызова метода format. Не верите, можете проверить. А если даже допустить, что вызов с null значением все же произойдет, то оно успешно будет обработано в одном из методов стека вызова, где есть возможность записать ошибку в лог и вернуть ошибку в протоколе взаимодействия.

Не нужно относится к своим коллегам с пренебрежением, впросак можете попасть, как коллега
foal

Мой комментарий на Вашу реплику ниже, не обновил страницу при ответе и он из за этого похоже попал не туда

Отвечу Вам той же монетой.

Ваше решение лишь только подтверждает мое утверждение, что и в пакете java.time нет удобного способа преобразования микро/нано секунд для Timestamp.

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

И вишенка на торте - NullPointerException. У меня к Вам три вопроса.

  1. Очень любопытно, а что Вы собрались или предполагаете делать с NullPointerException в моем коде, когда пишите "проверка на null"? Могу предположить такой вариант

if (source == null) return null;

Угадал?

  1. Почему у Вас возник вопрос только про NullPointerException? ParseException ведь тоже не обрабатывается в предложенном мной варианте решения, если, как Вы пишите, придерживаться вашей "авторской нотации". В чем в данном случае разница между этими два исключениями?

  2. А если все же немножко подумать? А если подумать, то NullPointerException в этом участке кода никогда не возникнет и любая проверка на null будет мертвым кодом. Спросите почему? А это я Вам оставлю в качестве домашнего задания, Вы же гуру, думаю, справитесь. Так как, справитесь?

Дополню. Лучший способ повышения производительности - исключить лишние преобразования. При преобразовании Timestamp это легко можно сделать без потери качества данных. Передавать Timestamp как число.

см комментарий выше, не правильно ответил на ваш вопрос

Нет, не сравнивал. Моих же собственных преобразований практически нет. Все основные преобразования делаются классом SimpleDateFormat. Устаревший или не устаревший этот класс ? Это определяется целью его использования. На мой взгляд, пользоваться им очень удобно при использовании JDBC.

В РЖД планово разгоняют своих IT специалистов. Это, наверное, единственная крупная компания, которая целенаправленно сокращает свой IT потенциал.

Информация

В рейтинге
Не участвует
Откуда
Нижний Новгород, Нижегородская обл., Россия
Зарегистрирован
Активность