День пятьсот шестьдесят первый. #Оффтоп
Единственный Фактор, Который Сделает Вас Сеньором
Недавно я видел курс на Udemy, который обещал сделать из вас мидла или сеньора. Что там было? Множество технологий. Множество тем. Идея заключалась в том, чтобы пробежаться по верхам большого количества ПО и концепций программирования, чтобы в итоге превратиться в сеньора!
Проблема в том, что вырасти как разработчик так не получится. В первую очередь потому, что большинство из нас к концу курса забудет то, что мы узнали в начале. Мы не используем эти технологии в нашей работе или повседневной деятельности, а то, что вы не используете, вы теряете.
Другая причина, по которой этот подход не работает, в том, что сеньоры не должны знать всё. У них нет ответов на все вопросы. Я помню, когда сам столкнулся с этим на моей первой работе в сфере корпоративного ПО после многих лет работы фрилансером. Однажды на планёрке менеджер проекта спросил, может ли один из сеньоров взять на себя новую задачу. Удивительно, но он сказал: «У меня нет опыта работы с X, и я думаю, что было бы лучше передать его кому-нибудь другому, кто в этом больше понимает». Я был шокирован! То есть сеньоры знают не всё? То есть они могут признать, что не могут что-то сделать или что кто-то другой знает больше? (Наивные мысли молодого разработчика). С тех пор я раз за разом был свидетелем того, как старшие разработчики передавали задачи младшим из-за недостатка знаний. Это не соревнование.
Итак, если он не всё знает, что делает его сеньором? Рассмотрим некоторые отличительные черты старших разработчиков:
1. Они хорошо видят «картину в целом» и поэтому важны в обсуждениях архитектуры на высоком уровне.
2. Они пишут чистый код.
3. Они могут вывести компанию или коллегу из ступора при возникновении проблем.
4. Они отказываются от ненужного или рискованного функционала.
5. Они с умом исследуют и могут выбрать нужную технологию.
6. Они могут оценить сроки проекта и разбить его на более мелкие части (которые отдадут младшим разработчикам).
7. Они знакомы с широким спектром технологий.
Секундочку! Последний пункт полностью противоречит первому утверждению о том, что вы не можете выучиться на сеньора. Нет. На самом деле можете. И это подводит меня к основной мысли.
Старший разработчик действительно знаком с широким спектром технологий.
Но этого нельзя достичь, пройдя курс. Вы не сможете повысить квалификацию в ускоренном режиме. Потому что в конечном итоге единственное, что делает вас сеньоров, — это ВРЕМЯ.
Это много лет работы над проектами, совершения ошибок, написания кода, сидения на собраниях, решения проблем и использования широкого спектра технологий. Это изучение концепций и основ программирования, которые позволяют вам легко ориентироваться в любой кодовой базе, помогать коллегам избавляться от проблем и нести ответственность за свои ошибки.
Всё это требует времени. Это зрелость, которую вы накапливаете за годы пребывания в окопах. Это титул, который вы зарабатываете в глазах других, а не который вы можете наградить себя сами.
Так что, если вы хотите стать старшим разработчиком, продолжайте выполнять работу, вкладывая время, совершая ошибки и извлекая уроки из всего этого. Наслаждайтесь временем в джунах, потому что это своего рода тренировочная площадка. Только время, проведённое в тренировках, рано или поздно сделает из вас сеньора.
Источник: https://medium.com/swlh/the-one-and-only-factor-that-will-make-you-a-senior-developer-4fdd9d21b8c4
Единственный Фактор, Который Сделает Вас Сеньором
Недавно я видел курс на Udemy, который обещал сделать из вас мидла или сеньора. Что там было? Множество технологий. Множество тем. Идея заключалась в том, чтобы пробежаться по верхам большого количества ПО и концепций программирования, чтобы в итоге превратиться в сеньора!
Проблема в том, что вырасти как разработчик так не получится. В первую очередь потому, что большинство из нас к концу курса забудет то, что мы узнали в начале. Мы не используем эти технологии в нашей работе или повседневной деятельности, а то, что вы не используете, вы теряете.
Другая причина, по которой этот подход не работает, в том, что сеньоры не должны знать всё. У них нет ответов на все вопросы. Я помню, когда сам столкнулся с этим на моей первой работе в сфере корпоративного ПО после многих лет работы фрилансером. Однажды на планёрке менеджер проекта спросил, может ли один из сеньоров взять на себя новую задачу. Удивительно, но он сказал: «У меня нет опыта работы с X, и я думаю, что было бы лучше передать его кому-нибудь другому, кто в этом больше понимает». Я был шокирован! То есть сеньоры знают не всё? То есть они могут признать, что не могут что-то сделать или что кто-то другой знает больше? (Наивные мысли молодого разработчика). С тех пор я раз за разом был свидетелем того, как старшие разработчики передавали задачи младшим из-за недостатка знаний. Это не соревнование.
Итак, если он не всё знает, что делает его сеньором? Рассмотрим некоторые отличительные черты старших разработчиков:
1. Они хорошо видят «картину в целом» и поэтому важны в обсуждениях архитектуры на высоком уровне.
2. Они пишут чистый код.
3. Они могут вывести компанию или коллегу из ступора при возникновении проблем.
4. Они отказываются от ненужного или рискованного функционала.
5. Они с умом исследуют и могут выбрать нужную технологию.
6. Они могут оценить сроки проекта и разбить его на более мелкие части (которые отдадут младшим разработчикам).
7. Они знакомы с широким спектром технологий.
Секундочку! Последний пункт полностью противоречит первому утверждению о том, что вы не можете выучиться на сеньора. Нет. На самом деле можете. И это подводит меня к основной мысли.
Старший разработчик действительно знаком с широким спектром технологий.
Но этого нельзя достичь, пройдя курс. Вы не сможете повысить квалификацию в ускоренном режиме. Потому что в конечном итоге единственное, что делает вас сеньоров, — это ВРЕМЯ.
Это много лет работы над проектами, совершения ошибок, написания кода, сидения на собраниях, решения проблем и использования широкого спектра технологий. Это изучение концепций и основ программирования, которые позволяют вам легко ориентироваться в любой кодовой базе, помогать коллегам избавляться от проблем и нести ответственность за свои ошибки.
Всё это требует времени. Это зрелость, которую вы накапливаете за годы пребывания в окопах. Это титул, который вы зарабатываете в глазах других, а не который вы можете наградить себя сами.
Так что, если вы хотите стать старшим разработчиком, продолжайте выполнять работу, вкладывая время, совершая ошибки и извлекая уроки из всего этого. Наслаждайтесь временем в джунах, потому что это своего рода тренировочная площадка. Только время, проведённое в тренировках, рано или поздно сделает из вас сеньора.
Источник: https://medium.com/swlh/the-one-and-only-factor-that-will-make-you-a-senior-developer-4fdd9d21b8c4
День пятьсот шестьдесят второй. #DotNetAZ
Dotnet A-Z. 6
В этой серии постов рассмотрим наиболее распространённые понятия в .NET в алфавитном порядке.
package (пакет)
Пакет NuGet или просто пакет - это файл архива с одной или несколькими сборками и дополнительными метаданными, такими как имя автора и описание.
Файл архива имеет расширение
platform (платформа)
Операционная система и оборудование, на котором она работает, например Windows, macOS, Linux, iOS и Android. Например: «.NET Core - это кроссплатформенная реализация .NET».
В документации .NET часто используется вариант «платформа .NET» для обозначения реализации .NET или стека .NET. Это создаёт путаницу с основным значением термина (ОС/оборудование), поэтому планируется исключить этот вариант использования из документации.
runtime (среда выполнения)
Среда выполнения управляемой программы. ОС является частью среды выполнения, но не частью среды выполнения .NET. Примеры сред выполнения .NET:
- Общеязыковая среда выполнения (CLR)
- Общеязыковая среда выполнения Core (CoreCLR)
- .NET Native (для UWP)
- Среда выполнения Mono
В документации иногда термин «среда выполнения» используется для обозначения реализации .NET. В этом случае под «средой выполнения .NET» следует понимать «реализацию .NET». Это несоответствие планируется устранить.
stack (стек)
Набор технологий программирования, которые используются совместно для создания и запуска приложений. Понятие «стек .NET» может означать как определённую реализацию .NET, так и .NET Standard и все реализации .NET в целом.
target framework (целевая платформа)
Набор API, на которые опирается приложение или библиотека .NET. Приложение или библиотека может быть нацелено на версию .NET Standard (например, .NET Standard 2.0), либо на версию конкретной реализации .NET. В последнем случае приложение получает доступ к набору API в этой конкретной реализации. Например, приложение, ориентированное на Xamarin.iOS, получает доступ к предоставляемым Xamarin оболочкам API для iOS.
Для некоторых целевых платформ (например, .NET Framework) доступные API-интерфейсы определяются сборками, установленными в системе, которые могут включать API-интерфейсы платформы приложений (например, ASP.NET или WinForms). Для целевых платформ на основе пакетов (таких как .NET Standard и .NET Core) API-интерфейсы платформы определяются пакетами, установленными в приложении или библиотеке. В этом случае целевая платформа неявно определяет метапакет, который содержит ссылки на все пакеты, составляющие платформу.
Источник: https://docs.microsoft.com/en-us/dotnet/standard/glossary
Dotnet A-Z. 6
В этой серии постов рассмотрим наиболее распространённые понятия в .NET в алфавитном порядке.
package (пакет)
Пакет NuGet или просто пакет - это файл архива с одной или несколькими сборками и дополнительными метаданными, такими как имя автора и описание.
Файл архива имеет расширение
.nupkg
и может содержать ресурсы, такие как файлы .dll
и .xml
, предназначенные для использования в определённых целевых платформах и версиях. При установке в приложении или библиотеке соответствующие ресурсы выбираются на основе целевой платформы приложения или библиотеки.platform (платформа)
Операционная система и оборудование, на котором она работает, например Windows, macOS, Linux, iOS и Android. Например: «.NET Core - это кроссплатформенная реализация .NET».
В документации .NET часто используется вариант «платформа .NET» для обозначения реализации .NET или стека .NET. Это создаёт путаницу с основным значением термина (ОС/оборудование), поэтому планируется исключить этот вариант использования из документации.
runtime (среда выполнения)
Среда выполнения управляемой программы. ОС является частью среды выполнения, но не частью среды выполнения .NET. Примеры сред выполнения .NET:
- Общеязыковая среда выполнения (CLR)
- Общеязыковая среда выполнения Core (CoreCLR)
- .NET Native (для UWP)
- Среда выполнения Mono
В документации иногда термин «среда выполнения» используется для обозначения реализации .NET. В этом случае под «средой выполнения .NET» следует понимать «реализацию .NET». Это несоответствие планируется устранить.
stack (стек)
Набор технологий программирования, которые используются совместно для создания и запуска приложений. Понятие «стек .NET» может означать как определённую реализацию .NET, так и .NET Standard и все реализации .NET в целом.
target framework (целевая платформа)
Набор API, на которые опирается приложение или библиотека .NET. Приложение или библиотека может быть нацелено на версию .NET Standard (например, .NET Standard 2.0), либо на версию конкретной реализации .NET. В последнем случае приложение получает доступ к набору API в этой конкретной реализации. Например, приложение, ориентированное на Xamarin.iOS, получает доступ к предоставляемым Xamarin оболочкам API для iOS.
Для некоторых целевых платформ (например, .NET Framework) доступные API-интерфейсы определяются сборками, установленными в системе, которые могут включать API-интерфейсы платформы приложений (например, ASP.NET или WinForms). Для целевых платформ на основе пакетов (таких как .NET Standard и .NET Core) API-интерфейсы платформы определяются пакетами, установленными в приложении или библиотеке. В этом случае целевая платформа неявно определяет метапакет, который содержит ссылки на все пакеты, составляющие платформу.
Источник: https://docs.microsoft.com/en-us/dotnet/standard/glossary
День пятьсот шестьдесят третий. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
55. Делайте Интерфейсы Удобными для Правильного Использования и Неудобными для Неправильного
Одна из наиболее распространённых задач при разработке ПО - это спецификация интерфейса. Интерфейсы возникают на самом высоком уровне абстракции (пользовательские интерфейсы), на самом низком (интерфейсы функций) и на промежуточных уровнях (интерфейсы классов, библиотек и т.д.). Независимо от того, работаете ли вы с конечными пользователями и определяете их взаимодействие с системой, пишете ли вы API для разработчиков или объявляете приватные функции класса, дизайн интерфейса является важной частью вашей работы. Если вы хорошо спроектируете интерфейс, он будет приятным для использования и повысит продуктивность других. Если вы сделаете это плохо, он будет источником разочарований и ошибок.
Хорошие интерфейсы:
1. Легко использовать правильно
Люди, использующие хорошо спроектированный интерфейс, почти всегда используют его правильно, потому что это путь наименьшего сопротивления. В графическом интерфейсе они почти всегда нажимают на правильную иконку, кнопку или пункт меню, потому что это очевидно и просто. Они почти всегда передают правильные параметры с правильными значениями в API, потому что это наиболее естественный вариант.
2. Трудно использовать неправильно
Хорошие интерфейсы предвидят ошибки, которые люди могут совершить, и усложняют их совершение, а, в идеале, делают их невозможными. Например, GUI может отключать или удалять элементы управления, которые не имеют смысла в текущем контексте; API может устранять проблемы с упорядочением аргументов, разрешая передачу параметров в любом порядке и т.п.
Хороший способ спроектировать интерфейсы, которые легко использовать правильно, - это испытать их до того, как они появятся. Создайте макет GUI, например, нарисовав на доске или на бумаге, и поиграйте с ним до того, как будет написан какой-либо код. Напишите вызовы API до написания функционала. Рассмотрите распространённые варианты использования и определите, как должен вести себя интерфейс. На что можно будет нажать в каждом конкретном случае? Что можно будет передать в метод? Простые в использовании интерфейсы кажутся естественными, потому что они позволяют делать то, что вы хотите. Вы с большей вероятностью придумаете такие интерфейсы, если будете разрабатывать их со стороны пользователя. Это одно из преимуществ разработки через тестирование.
Чтобы сделать интерфейсы трудными для неправильного использования, нужны две вещи. Во-первых, вы должны предвидеть ошибки, которые могут совершить пользователи, и найти способы их предотвращения. Во-вторых, понаблюдав за неправильным использованием интерфейса в тестовых версиях, вы должны изменить его, чтобы предотвратить такие ошибки. Лучший способ предотвратить неправильное использование - сделать такое использование невозможным. Если пользователи всё равно хотят отменить неотменяемое действие, попробуйте сделать его отменяемым. Если они упорно передают неправильное значение в API, сделайте всё возможное, чтобы изменить API, разрешив значения, которые пользователи хотят передать.
Главное, помните, что интерфейсы существуют для удобства их пользователей, а не их разработчиков.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Scott Meyers.
97 Вещей, Которые Должен Знать Каждый Программист
55. Делайте Интерфейсы Удобными для Правильного Использования и Неудобными для Неправильного
Одна из наиболее распространённых задач при разработке ПО - это спецификация интерфейса. Интерфейсы возникают на самом высоком уровне абстракции (пользовательские интерфейсы), на самом низком (интерфейсы функций) и на промежуточных уровнях (интерфейсы классов, библиотек и т.д.). Независимо от того, работаете ли вы с конечными пользователями и определяете их взаимодействие с системой, пишете ли вы API для разработчиков или объявляете приватные функции класса, дизайн интерфейса является важной частью вашей работы. Если вы хорошо спроектируете интерфейс, он будет приятным для использования и повысит продуктивность других. Если вы сделаете это плохо, он будет источником разочарований и ошибок.
Хорошие интерфейсы:
1. Легко использовать правильно
Люди, использующие хорошо спроектированный интерфейс, почти всегда используют его правильно, потому что это путь наименьшего сопротивления. В графическом интерфейсе они почти всегда нажимают на правильную иконку, кнопку или пункт меню, потому что это очевидно и просто. Они почти всегда передают правильные параметры с правильными значениями в API, потому что это наиболее естественный вариант.
2. Трудно использовать неправильно
Хорошие интерфейсы предвидят ошибки, которые люди могут совершить, и усложняют их совершение, а, в идеале, делают их невозможными. Например, GUI может отключать или удалять элементы управления, которые не имеют смысла в текущем контексте; API может устранять проблемы с упорядочением аргументов, разрешая передачу параметров в любом порядке и т.п.
Хороший способ спроектировать интерфейсы, которые легко использовать правильно, - это испытать их до того, как они появятся. Создайте макет GUI, например, нарисовав на доске или на бумаге, и поиграйте с ним до того, как будет написан какой-либо код. Напишите вызовы API до написания функционала. Рассмотрите распространённые варианты использования и определите, как должен вести себя интерфейс. На что можно будет нажать в каждом конкретном случае? Что можно будет передать в метод? Простые в использовании интерфейсы кажутся естественными, потому что они позволяют делать то, что вы хотите. Вы с большей вероятностью придумаете такие интерфейсы, если будете разрабатывать их со стороны пользователя. Это одно из преимуществ разработки через тестирование.
Чтобы сделать интерфейсы трудными для неправильного использования, нужны две вещи. Во-первых, вы должны предвидеть ошибки, которые могут совершить пользователи, и найти способы их предотвращения. Во-вторых, понаблюдав за неправильным использованием интерфейса в тестовых версиях, вы должны изменить его, чтобы предотвратить такие ошибки. Лучший способ предотвратить неправильное использование - сделать такое использование невозможным. Если пользователи всё равно хотят отменить неотменяемое действие, попробуйте сделать его отменяемым. Если они упорно передают неправильное значение в API, сделайте всё возможное, чтобы изменить API, разрешив значения, которые пользователи хотят передать.
Главное, помните, что интерфейсы существуют для удобства их пользователей, а не их разработчиков.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Scott Meyers.
День пятьсот шестьдесят четвёртый. #MoreEffectiveCSharp
16. Реализуйте Паттерн Событий для Уведомлений. Начало
Паттерн событий в .NET - это лишь соглашения о синтаксисе в паттерне Наблюдатель. События определяют уведомления для вашего типа. Они основаны на делегатах, чтобы обеспечить типобезопасные сигнатуры функций для обработчиков событий. События используются, когда ваш тип должен общаться с несколькими клиентами, чтобы информировать их о происходящем в системе.
Например, вы создаёте класс, который действует как диспетчер всех сообщений в приложении. Он принимает все сообщения из источников в вашем приложении и отправляет их всем заинтересованным клиентам. Клиенты могут быть подключены к консоли, базе данных, системному журналу или какому-либо другому механизму:
Следующий упрощённый класс является примером подписчика. Он подписывается в статическом конструкторе и передаёт делегат, направляющий все сообщения в консоль:
Пример использования:
Источник: Bill Wagner “More Effective C#”. – 2nd ed. Глава 15.
16. Реализуйте Паттерн Событий для Уведомлений. Начало
Паттерн событий в .NET - это лишь соглашения о синтаксисе в паттерне Наблюдатель. События определяют уведомления для вашего типа. Они основаны на делегатах, чтобы обеспечить типобезопасные сигнатуры функций для обработчиков событий. События используются, когда ваш тип должен общаться с несколькими клиентами, чтобы информировать их о происходящем в системе.
Например, вы создаёте класс, который действует как диспетчер всех сообщений в приложении. Он принимает все сообщения из источников в вашем приложении и отправляет их всем заинтересованным клиентам. Клиенты могут быть подключены к консоли, базе данных, системному журналу или какому-либо другому механизму:
public class Logger {Метод
static Logger() {
Singleton = new Logger();
}
private Logger(){}
public static Logger Singleton { get; }
// Определяем событие:
public event EventHandler<LoggerEventArgs> Log;
// добавляем сообщение
public void AddMsg(int priority, string msg) =>
Log?.Invoke(this, new LoggerEventArgs(priority, msg));
}
AddMsg
использует оператор ?., который позволяет убедиться, что событие возникает только если на него подписаны наблюдатели.LoggerEventArgs
содержит свойства для приоритета и текста сообщения:public class LoggerEventArgs : EventArgs {Внутри класса Logger поле event определяет обработчик событий. Компилятор видит определение публичного поля
public LoggerEventArgs(int priority, string msg) {
Priority = priority;
Message = msg;
}
public int Priority { get; }
public string Message { get; }
}
event
и создаёт для вас операторы Add
(+=
) и Remove
(-=
) для подписки и отписки, которые гарантированно являются потокобезопасными.Следующий упрощённый класс является примером подписчика. Он подписывается в статическом конструкторе и передаёт делегат, направляющий все сообщения в консоль:
class ConsoleLogger {События уведомляют любое количество заинтересованных клиентов о том, что что-то произошло. При этом классу
static ConsoleLogger() =>
Logger.Singleton.Log += (sender, msg) =>
Console.WriteLine("{0}:\t{1}",
msg.Priority.ToString(),
msg.Message);
}
Logger
не требуется никаких предварительных знаний о том, какие объекты заинтересованы в регистрации событий. Пример использования:
var cl = new ConsoleLogger();Продолжение следует…
Logger.Singleton.AddMsg(1, "test message");
Источник: Bill Wagner “More Effective C#”. – 2nd ed. Глава 15.
День пятьсот шестьдесят пятый. #MoreEffectiveCSharp
16. Реализуйте Паттерн Событий для Уведомлений. Окончание
Начало
Класс
Вместо
16. Реализуйте Паттерн Событий для Уведомлений. Окончание
Начало
Класс
Logger
содержал только одно событие. Есть классы, которые имеют большое количество событий (у компонентов UI их может быть до сотни). Тогда использовать отдельное поле для каждого события неприемлемо. В приложении фактически используется лишь небольшая часть из них. В этом случае можно создавать объекты событий во время выполнения только при необходимости. Добавим в класс Logger
указание подсистемы, отправляющей сообщения. Клиенты будут регистрироваться на сообщения определённой подсистемы. Обновлённый метод AddMsg()
теперь принимает строковый параметр, обозначающий подсистему, отправившую сообщение. Кроме того, будет вызываться событие с ключом в виде пустой строки для подписчиков на сообщения от всех подсистем:public class Logger {В этом примере отдельные обработчики событий хранятся в коллекции
private static EventHandlerList
Handlers = new EventHandlerList();
static public void AddLogger(string system,
EventHandler<LoggerEventArgs> ev) =>
Handlers.AddHandler(system, ev);
static public void RemoveLogger(string system,
EventHandler<LoggerEventArgs> ev) =>
Handlers.RemoveHandler(system, ev);
static public void AddMsg(string system,
int priority, string msg){
if (!string.IsNullOrEmpty(system)) {
EventHandler<LoggerEventArgs> handler =
Handlers[system] as
EventHandler<LoggerEventArgs>;
LoggerEventArgs args =
new LoggerEventArgs(priority, msg);
handler?.Invoke(null, args);
// для получателей всех сообщений
handler = Handlers[""] as
EventHandler<LoggerEventArgs>;
handler?.Invoke(null, args);
}
}
}
EventHandlerList
. Клиенты подписываются на события подсистемы через AddLogger
, передавая ему строковое имя подсистемы и свой делегат обработки сообщения. Первый вызов создаёт событие для подсистемы, последующие вызовы используют это событие. К сожалению, не существует обобщённой версии EventHandlerList
, поэтому в AddMsg
приходится использовать приведение типов для элементов коллекции.Вместо
EventHandlerList
можно использовать словарь Dictionary<string, EventHandler<LoggerEventArgs>>
, что добавит немного кода, но позволит использовать строгую типизацию:…Источник: Bill Wagner “More Effective C#”. – 2nd ed. Глава 15.
static public void AddLogger(string system,
EventHandler<LoggerEventArgs> ev) {
if (Handlers.ContainsKey(system))
Handlers[system] += ev;
else
Handlers.Add(system, ev);
}
…
static public void AddMsg(…) {
if (string.IsNullOrEmpty(system)) {
EventHandler<LoggerEventArgs> handler = null;
Handlers.TryGetValue(system, out handler);
…
}
}
День пятьсот шестьдесят шестой. #ЗадачиНаСобеседовании
Топ 10 Умений Которые Понадобятся на Собеседовании
На собеседовании вам могут как задать самые разные вопросы по теории, так и дать практическое задание. Некоторые из них я уже приводил на канале: 1, 2, 3, 4.
Заучить их все просто нереально. Но большинство из них тестирует одно из следующих базовых умений, которым должен обладать каждый «уважающий себя» программист.
1. Двоичный (бинарный) поиск — классический алгоритм поиска элемента в отсортированном массиве, использующий дробление массива на половины. Используется не только в элементарном нахождении элемента в отсортированном массиве. Он встречается настолько часто, что может быть скрыт даже в задании не на кодирование. К примеру, нужно найти в логах git версию, где в приложении допущена ошибка.
2. Умение строить структуры данных. Практически во всех задачах требуется правильная инкапсуляция данных. Особенно это относится к ООП. Иногда сложность задачи даже не столько в алгоритме, сколько в построении правильной структуры или класса. Поэтому без умения создавать лаконичные и непротиворечивые структуры данных никуда.
3. Рекурсия. Несмотря на то, что рекурсия – тема множества мемов и шуточек про программистов, в реальности она встречается довольно редко (а в таких мемах – почти никогда). Есть хорошее выражение: «Существует несколько задач, которые красиво и эффективно решаются рекурсией. Есть множество задач, которые красиво, но неэффективно решаются рекурсией. Подавляющее большинство задач решать рекурсией и некрасиво, и неэффективно». Тем не менее, знать принципы рекурсивного решения очень полезно. Пример: решение судоку.
4. Основы сортировки. Это не значит, что вам нужно заучить алгоритмы сортировки слиянием или быстрой сортировки. Но важно понимать общие принципы работы, почему сортировка слиянием быстрее сортировки пузырьком, время работы в O-нотации, уметь использовать факт, что коллекция уже отсортирована и т.п.
5. Разворачивание связанного списка. Вариантами задачи могут быть нахождение дубликатов в списке или определение, является ли связанный список зацикленным. Кроме того, важно правильно создать структуру элемента списка (данные и указатель).
6. Манипулирование несколькими переменными/указателями одновременно. Канонический пример: разворот строки, определение, является ли строка палиндромом, нахождение самого длинного палиндрома в тексте, - движение указателей в обе стороны, либо с разной скоростью.
7. Использование Хеш-таблиц (или множеств). Здесь вариантами могут быть задачи на оптимальное нахождение парного числа в массиве, задачи на обход графа с сохранением пути, мемоизация в рекурсии и т.п.
8. Нахождение закрывающей скобки. Вариантами могут быть проверка, все ли скобки закрыты в строке, либо нахождение, сколько скобок нужно добавить. Кандидат для использования стека. Добавляем открывающие скобки в стек, при нахождении закрывающей скобки – удаляем элемент из стека.
9. Поиск в глубину (Depth-first search) — один из методов обхода графа, который состоит в том, чтобы идти «вглубь» графа, насколько это возможно. Можно реализовать с помощью стека и рекурсии. Для заданной вершины добавляем всех её потомков в стек, далее извлекаем первый элемент стека и повторяем процедуру для него рекурсивно.
10. Поиск в ширину (Breadth-first search) — обход всех ребер для «открытия» всех вершин, достижимых из заданной вершины. Можно реализовать с помощью очереди. Для заданной вершины добавляем всех её потомков в очередь. Далее, проходя по очереди добавляем всех потомков каждого элемента в конец очереди.
Источники:
- https://www.youtube.com/watch?v=r1MXwyiGi_U
- https://youtu.be/zHczhZn-z30
Топ 10 Умений Которые Понадобятся на Собеседовании
На собеседовании вам могут как задать самые разные вопросы по теории, так и дать практическое задание. Некоторые из них я уже приводил на канале: 1, 2, 3, 4.
Заучить их все просто нереально. Но большинство из них тестирует одно из следующих базовых умений, которым должен обладать каждый «уважающий себя» программист.
1. Двоичный (бинарный) поиск — классический алгоритм поиска элемента в отсортированном массиве, использующий дробление массива на половины. Используется не только в элементарном нахождении элемента в отсортированном массиве. Он встречается настолько часто, что может быть скрыт даже в задании не на кодирование. К примеру, нужно найти в логах git версию, где в приложении допущена ошибка.
2. Умение строить структуры данных. Практически во всех задачах требуется правильная инкапсуляция данных. Особенно это относится к ООП. Иногда сложность задачи даже не столько в алгоритме, сколько в построении правильной структуры или класса. Поэтому без умения создавать лаконичные и непротиворечивые структуры данных никуда.
3. Рекурсия. Несмотря на то, что рекурсия – тема множества мемов и шуточек про программистов, в реальности она встречается довольно редко (а в таких мемах – почти никогда). Есть хорошее выражение: «Существует несколько задач, которые красиво и эффективно решаются рекурсией. Есть множество задач, которые красиво, но неэффективно решаются рекурсией. Подавляющее большинство задач решать рекурсией и некрасиво, и неэффективно». Тем не менее, знать принципы рекурсивного решения очень полезно. Пример: решение судоку.
4. Основы сортировки. Это не значит, что вам нужно заучить алгоритмы сортировки слиянием или быстрой сортировки. Но важно понимать общие принципы работы, почему сортировка слиянием быстрее сортировки пузырьком, время работы в O-нотации, уметь использовать факт, что коллекция уже отсортирована и т.п.
5. Разворачивание связанного списка. Вариантами задачи могут быть нахождение дубликатов в списке или определение, является ли связанный список зацикленным. Кроме того, важно правильно создать структуру элемента списка (данные и указатель).
6. Манипулирование несколькими переменными/указателями одновременно. Канонический пример: разворот строки, определение, является ли строка палиндромом, нахождение самого длинного палиндрома в тексте, - движение указателей в обе стороны, либо с разной скоростью.
7. Использование Хеш-таблиц (или множеств). Здесь вариантами могут быть задачи на оптимальное нахождение парного числа в массиве, задачи на обход графа с сохранением пути, мемоизация в рекурсии и т.п.
8. Нахождение закрывающей скобки. Вариантами могут быть проверка, все ли скобки закрыты в строке, либо нахождение, сколько скобок нужно добавить. Кандидат для использования стека. Добавляем открывающие скобки в стек, при нахождении закрывающей скобки – удаляем элемент из стека.
9. Поиск в глубину (Depth-first search) — один из методов обхода графа, который состоит в том, чтобы идти «вглубь» графа, насколько это возможно. Можно реализовать с помощью стека и рекурсии. Для заданной вершины добавляем всех её потомков в стек, далее извлекаем первый элемент стека и повторяем процедуру для него рекурсивно.
10. Поиск в ширину (Breadth-first search) — обход всех ребер для «открытия» всех вершин, достижимых из заданной вершины. Можно реализовать с помощью очереди. Для заданной вершины добавляем всех её потомков в очередь. Далее, проходя по очереди добавляем всех потомков каждого элемента в конец очереди.
Источники:
- https://www.youtube.com/watch?v=r1MXwyiGi_U
- https://youtu.be/zHczhZn-z30
День пятьсот шестьдесят седьмой. #ЧтоНовенького #CSharp9
Первичные Конструкторы в C#9
В C#9 представлен новый упрощённый способ создания классов. Большинство конструкторов очень избыточны, поскольку аргументы конструктора чаще всего используются только для инициализации свойств с тем же именем. Теперь есть способ избавиться от этого лишнего кода. Сейчас мы пишем что-то вроде этого:
Инициализаторы
Первичные конструкторы также используют новые init-свойства. Это означает, что мы можем установить значение свойства с помощью инициализатора объекта:
В первичный конструктор можно передавать значения по умолчанию:
Источник: https://blog.miguelbernard.com/c-9-0-primary-constructors/
Первичные Конструкторы в C#9
В C#9 представлен новый упрощённый способ создания классов. Большинство конструкторов очень избыточны, поскольку аргументы конструктора чаще всего используются только для инициализации свойств с тем же именем. Теперь есть способ избавиться от этого лишнего кода. Сейчас мы пишем что-то вроде этого:
public class Person {8 строк кода (11, если переносить открывающую скобку на новую строку), только чтобы создать простой POCO (Plain Old CLR Object). Теперь это можно сделать в одну строку:
public Person(string firstName, string lastName) {
this.FirstName = firstName;
this.LastName = lastName;
}
public string FirstName { get; }
public string LastName { get; }
}
public record Person(string firstName, string lastName);На момент написания первичные конструкторы доступны только для записей. Классы и структуры пока не поддерживаются, но должны быть реализованы в окончательной версии.
Инициализаторы
Первичные конструкторы также используют новые init-свойства. Это означает, что мы можем установить значение свойства с помощью инициализатора объекта:
var p = new Person("Miguel", "Bernard") { lastName = "test" };Это работает, как и ожидалось. После выполнения конструктора значение
"Bernard"
заменяется на "test"
. Однако вы не можете использовать инициализатор объекта для задания обязательных свойств первичного конструктора:// Это не скомпилируетсяЗначения по умолчанию
var p = new Person("Miguel") { lastName = "test" };
В первичный конструктор можно передавать значения по умолчанию:
public record Person (string firstName, string lastName = "lastName");Я вижу большой потенциал в этой новой функции, особенно для POCO/DTO и простых объектов. Удаление всего этого бесполезного шаблонного кода сократит издержки при создании новых типов и упростит кодовую базу.
var p = new Person("Miguel");
Источник: https://blog.miguelbernard.com/c-9-0-primary-constructors/
👍2
День пятьсот шестьдесят восьмой. #ЧтоНовенького #CSharp9
Подробнее про Записи в C#9
Записи в C#9 помогут нам создавать неизменяемые типы, которые очень полезны в большой распределенной архитектуре. Поскольку запись ведет себя иначе, чем класс или структура, Microsoft ввели новое ключевое слово
Ещё интереснее использование записей с первичными конструкторами:
With
С введением записей добавится ещё одно ключевое слово with, которое позволит «клонировать» запись, изменив только некоторые свойства.
Записи обладают структурным равенством, то есть две записи считаются равными, если все их свойства равны. Такое поведение сложно реализовать с помощью классических классов, поскольку нужно переопределить методы
Деконструкция
Записи также поддерживают деконструкцию, что позволяет неявно преобразовать запись в кортеж, содержащий все свойства:
Наследование
Поскольку C# - объектно-ориентированный язык, наследование является частью ООП, и его следует поддерживать. Должно быть, это самая серьёзная проблема, которую пришлось преодолеть команде C#, - сделать записи частью языка, сохранив при этом обратную совместимость.
Заметьте, что невозможно смешивать классы и записи в цепочке наследования (наследовать класс от записи или наоборот). Однако, вполне возможно, чтобы запись реализовывала интерфейс:
На момент написания невозможно использовать ключевое слово record для ограничения обобщения:
Источник: https://blog.miguelbernard.com/c-9-0-records/
Подробнее про Записи в C#9
Записи в C#9 помогут нам создавать неизменяемые типы, которые очень полезны в большой распределенной архитектуре. Поскольку запись ведет себя иначе, чем класс или структура, Microsoft ввели новое ключевое слово
record
.public record Chicken { public string Name {get;init;} }Первичные конструкторы
var c = new Chicken { Name = "test" };
// c.Name = "t"; - изменение значения недопустимо
Ещё интереснее использование записей с первичными конструкторами:
public record Chicken(string name);Фактически есть большой соблазн использовать только первичные конструкторы для объявления записей, чтобы отличать их от объявления классов.
With
С введением записей добавится ещё одно ключевое слово with, которое позволит «клонировать» запись, изменив только некоторые свойства.
var c2 = c with { Name = "myNewName" };Структурное равенство
Записи обладают структурным равенством, то есть две записи считаются равными, если все их свойства равны. Такое поведение сложно реализовать с помощью классических классов, поскольку нужно переопределить методы
Equals
и GetHashCode
и обновлять код этих методов при изменении свойств.Деконструкция
Записи также поддерживают деконструкцию, что позволяет неявно преобразовать запись в кортеж, содержащий все свойства:
public record Decons(int qty, string name, DateTime time);Того же результата можно достичь с помощью метода
var r = new Decons(42, "name", DateTime.Now);
var(x, y, z) = r;
Deconstruct()
, доступного для всех типов записей.Наследование
Поскольку C# - объектно-ориентированный язык, наследование является частью ООП, и его следует поддерживать. Должно быть, это самая серьёзная проблема, которую пришлось преодолеть команде C#, - сделать записи частью языка, сохранив при этом обратную совместимость.
public abstract record Food (int Cal);При этом можно обратиться как к
public record Milk(int C, double Fat) : Food(C);
var m = new Milk(1, 3.25);
m.C
, так и к m.Cal
(они будут равны 1). Но что, если объявить свойства одинаково?public record Milk(int Cal, double Fat) : Food(Cal);У вас останется одно свойство
Cal
, причём оно будет наследовано от Food
. Думаю, это наиболее логичное поведение.Заметьте, что невозможно смешивать классы и записи в цепочке наследования (наследовать класс от записи или наоборот). Однако, вполне возможно, чтобы запись реализовывала интерфейс:
public interface IRecord { }Ограничения обобщений
public record RecordType : IRecord { }
На момент написания невозможно использовать ключевое слово record для ограничения обобщения:
public void Method<T>(T t) where T : recordНадеюсь, к моменту выхода 9й версии это будет поддерживаться.
Источник: https://blog.miguelbernard.com/c-9-0-records/
👍3
День пятьсот шестьдесят девятый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
56. Делайте Невидимое Видимым
Многие аспекты невидимости справедливо относят к важным принципам разработки программного обеспечения, которых необходимо придерживаться. Наша терминология богата метафорами невидимости: ссылочная прозрачность или сокрытие информации – лишь пара примеров. ПО и процесс его разработки могут быть по большей части невидимы:
- Исходный код не имеет физической сущности, поведения и не подчиняется законам физики. Он виден, когда вы загружаете его в редактор, но закройте редактор, и он исчезнет. Как дерево, которое падает, но этого никто не слышит, можно начать сомневаться, а существует ли оно вообще.
- Работающее приложение имеет сущность и поведение, но не раскрывает ничего о своём исходном коде. Домашняя страница Google приятно минималистична, но её функционал, несомненно, огромен.
- Если вы сделали 90% задачи, но застряли, пытаясь отладить последние 10%, то нельзя сказать, что продукт готов на 90%. Исправление ошибок не считается прогрессом. Вам не платят за отладку. Отладка - пустая трата времени. Хорошо бы сделать эти потери более заметными, чтобы вы могли сразу видеть, куда тратятся ресурсы, и думать о том, как этого не допускать.
- Если ваш проект всё время продвигался по плану, а через неделю уже опаздывает на шесть месяцев, у вас проблемы. И самая большая проблема даже не в том, что проект опаздывает на шесть месяцев, а том, что вы не заметили причины задержки до самого последнего момента! Отсутствие видимого прогресса является синонимом отсутствия прогресса.
Невидимость может быть опасной. Вы размышляете яснее, когда у вас есть что-то конкретное, с чем можно связать своё мышление. Вы лучше управляете вещами, когда видите их и видите, как они постоянно меняются:
- Написание модульных тестов свидетельствует о том, насколько легко блок кода поддаётся тестированию. Это помогает выявить наличие (или отсутствие) качеств, которые вы хотели бы иметь в коде, таких как низкая связанность и высокая связность.
- Выполнение модульных тестов свидетельствует о поведении кода. Это помогает выявить наличие (или отсутствие) качеств времени выполнения, которые вы хотели бы иметь в приложении, таких как надёжность и корректность.
- Использование общедоступного баг трекера делает прогресс видимым и конкретным. Задачи могут отображаться как «Не начата», «Выполняется» или «Выполнена», вне зависимости от наличия скрытого инструмента управления проектом и без необходимости преследовать программистов за недостоверные отчёты о выполненной работе.
- Инкрементальная разработка улучшает видимость прогресса (или его отсутствия) за счёт увеличения частоты релизов (свидетельств прогресса). Завершение и выпуск ПО показывает реальную картину, оценка прогресса - нет.
Лучше всего разрабатывать программное обеспечение с большим количеством регулярных видимых доказательств. Видимость даёт уверенность в том, что прогресс является подлинным, а не иллюзорным, запланированным, а не случайным, повторяемым и не разовым.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Jon Jagger.
97 Вещей, Которые Должен Знать Каждый Программист
56. Делайте Невидимое Видимым
Многие аспекты невидимости справедливо относят к важным принципам разработки программного обеспечения, которых необходимо придерживаться. Наша терминология богата метафорами невидимости: ссылочная прозрачность или сокрытие информации – лишь пара примеров. ПО и процесс его разработки могут быть по большей части невидимы:
- Исходный код не имеет физической сущности, поведения и не подчиняется законам физики. Он виден, когда вы загружаете его в редактор, но закройте редактор, и он исчезнет. Как дерево, которое падает, но этого никто не слышит, можно начать сомневаться, а существует ли оно вообще.
- Работающее приложение имеет сущность и поведение, но не раскрывает ничего о своём исходном коде. Домашняя страница Google приятно минималистична, но её функционал, несомненно, огромен.
- Если вы сделали 90% задачи, но застряли, пытаясь отладить последние 10%, то нельзя сказать, что продукт готов на 90%. Исправление ошибок не считается прогрессом. Вам не платят за отладку. Отладка - пустая трата времени. Хорошо бы сделать эти потери более заметными, чтобы вы могли сразу видеть, куда тратятся ресурсы, и думать о том, как этого не допускать.
- Если ваш проект всё время продвигался по плану, а через неделю уже опаздывает на шесть месяцев, у вас проблемы. И самая большая проблема даже не в том, что проект опаздывает на шесть месяцев, а том, что вы не заметили причины задержки до самого последнего момента! Отсутствие видимого прогресса является синонимом отсутствия прогресса.
Невидимость может быть опасной. Вы размышляете яснее, когда у вас есть что-то конкретное, с чем можно связать своё мышление. Вы лучше управляете вещами, когда видите их и видите, как они постоянно меняются:
- Написание модульных тестов свидетельствует о том, насколько легко блок кода поддаётся тестированию. Это помогает выявить наличие (или отсутствие) качеств, которые вы хотели бы иметь в коде, таких как низкая связанность и высокая связность.
- Выполнение модульных тестов свидетельствует о поведении кода. Это помогает выявить наличие (или отсутствие) качеств времени выполнения, которые вы хотели бы иметь в приложении, таких как надёжность и корректность.
- Использование общедоступного баг трекера делает прогресс видимым и конкретным. Задачи могут отображаться как «Не начата», «Выполняется» или «Выполнена», вне зависимости от наличия скрытого инструмента управления проектом и без необходимости преследовать программистов за недостоверные отчёты о выполненной работе.
- Инкрементальная разработка улучшает видимость прогресса (или его отсутствия) за счёт увеличения частоты релизов (свидетельств прогресса). Завершение и выпуск ПО показывает реальную картину, оценка прогресса - нет.
Лучше всего разрабатывать программное обеспечение с большим количеством регулярных видимых доказательств. Видимость даёт уверенность в том, что прогресс является подлинным, а не иллюзорным, запланированным, а не случайным, повторяемым и не разовым.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Jon Jagger.
👍1
День пятьсот семидесятый. #TipsAndTricks
Повышаем продуктивность в Visual Studio.
31. Отслеживать или не Отслеживать Текущий Документ в Проводнике Решения
Может быть очень полезно переключаться на текущий файл в проводнике решения (Tools -> Options -> Projects and Solutions -> General -> Track Active Item in Solution Explorer). Последнее, что хочется делать, - это вручную искать его в дереве элементов вашего решения.
Проблема в том, что после работы с кучей файлов дерево проводника решения превращается в бардак. Всё развернуто и ничего не найти. Вместо автоматического отслеживания есть горячие клавиши для перехода к этому элементу.
Горячие клавиши по умолчанию -
Источник: https://michaelscodingspot.com/productivity-tips-in-visual-studio/
Повышаем продуктивность в Visual Studio.
31. Отслеживать или не Отслеживать Текущий Документ в Проводнике Решения
Может быть очень полезно переключаться на текущий файл в проводнике решения (Tools -> Options -> Projects and Solutions -> General -> Track Active Item in Solution Explorer). Последнее, что хочется делать, - это вручную искать его в дереве элементов вашего решения.
Проблема в том, что после работы с кучей файлов дерево проводника решения превращается в бардак. Всё развернуто и ничего не найти. Вместо автоматического отслеживания есть горячие клавиши для перехода к этому элементу.
Горячие клавиши по умолчанию -
Ctrl+[,S
. Я стараюсь оставлять значения по умолчанию. Не самая простая для запоминания комбинация, но ко всему привыкаешь. Как бы то ни было, поменять можно в Tools -> Options -> Environment -> Keyboard. Начните вводить "SyncWithActiveDocument
" в поле справа.Источник: https://michaelscodingspot.com/productivity-tips-in-visual-studio/
День пятьсот семьдесят первый. #ЗаметкиНаПолях
Деревья выражений
Деревья выражений - чрезвычайно мощная часть .NET, но они также являются одной из самых плохо понимаемых частей. По сути, они позволяют вам обернуть лямбда-выражения, такие как
Давайте рассмотрим что-нибудь попроще. Допустим, у вас есть код, который добавляет настройки в словарь:
Очевидно, это только малая толика того, на что способны деревья выражений.
Источник: https://chrisstclair.co.uk/6-lesser-known-features-of-c-net-that-you-should-be-using/
Деревья выражений
Деревья выражений - чрезвычайно мощная часть .NET, но они также являются одной из самых плохо понимаемых частей. По сути, они позволяют вам обернуть лямбда-выражения, такие как
Func<T>
или Action<T>
, и проанализировать их. Лучше всего проиллюстрировать это на примере. Метод расширения Where
в LINQ to Objects принимает Func<T, int, bool>
в качестве основного параметра:static IEnumerable<TSource> WhereIterator<TSource>(IEnumerable<TSource> source, Func<TSource, int, bool> predicate) {Он выполняет итерацию по
int index = -1;
foreach (TSource element in source) {
checked { index++; }
if (predicate(element, index)) yield return element;
}
}
IEnumerable
и возвращает элементы соответствующие предикату. Однако очевидно, что это не будет работать в LINQ to SQL/Entity Framework, т.к. там необходимо перевести предикат в SQL! Так что сигнатура для версии IQueryable
немного другая:static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, int, bool>> predicate) {Выглядит страшно, но главное тут в том, что функция теперь принимает делегат
return source.Provider.CreateQuery<TSource>(
Expression.Call(
null,
GetMethodInfo(Queryable.Where, source, predicate),
new Expression[] {
source.Expression, Expression.Quote(predicate)
}
)
);
}
Func<T, int, bool>
, завернутый в Expression
, то есть позволяет LINQ провайдеру прочитать Func, проанализировать переданный предикат и перевести его в SQL. Таким образом, Expression
позволяет вам проверять ваш код во время выполнения.Давайте рассмотрим что-нибудь попроще. Допустим, у вас есть код, который добавляет настройки в словарь:
var settings = new List<Setting>();Здесь нетрудно увидеть опасность: название параметра в словаре представляет собой строку, и опечатка здесь может вызвать проблемы. Если мы создадим новый метод, который принимает
settings.Add(
new Setting(
"EnableBugs",
Settings.EnableBugs));
settings.Add(
new Setting(
"EnableFluxCapacitor",
Settings.EnableFluxCapacitor));
Expression<Func<T>>
(т.е. лямбда-выражение, которое что-то возвращает), мы можем получить фактическое имя переданной переменной:private Setting GetSetting<T>(Expression<Func<T>> expr) {Вызов:
var me = expr.Body as MemberExpression;
if (me == null)
throw new ArgumentException("Invalid expression.");
//переводим выражение обратно в Func
var func = expr.Compile();
//выполняем func, чтобы получить значение
var value = func();
return new Setting(me.Member.Name,value);
}
var settings = new List<Setting>();Заметьте, что нужно проверить, передано ли выражение типа
settings.Add(GetSetting(() => Settings.EnableBugs));
settings.Add(GetSetting(() => Settings.EnableFluxCapacitor));
MemberExpression
(обращение к свойству), т.к ничто не мешает вызывающему коду передать любой другой подходящий делегат, тогда нельзя будет обратиться к .Member.Name
.Очевидно, это только малая толика того, на что способны деревья выражений.
Источник: https://chrisstclair.co.uk/6-lesser-known-features-of-c-net-that-you-should-be-using/
👍2
День пятьсот семьдесят второй. #TipsAndTricks
Повышаем продуктивность в Visual Studio.
32. Хитрости Ctrl+T
Есть много способов навигации по вашему решению. Мой любимый способ - это сочетание клавиш
В этом окне есть несколько хитростей:
- Обычный поиск использует простую логику «содержит». Если файл/класс/член содержит текст из поля для поиска, он появится в результатах.
- Для элементов, написанных с помощью
- Вы можете сузить поиск до определенных типов результатов:
Источник: https://michaelscodingspot.com/productivity-tips-in-visual-studio/
Повышаем продуктивность в Visual Studio.
32. Хитрости Ctrl+T
Есть много способов навигации по вашему решению. Мой любимый способ - это сочетание клавиш
Ctrl+T
(Edit > Go To > Go To All…). Вы можете искать всё, что хотите: файл, класс, свойство, поле или метод.В этом окне есть несколько хитростей:
- Обычный поиск использует простую логику «содержит». Если файл/класс/член содержит текст из поля для поиска, он появится в результатах.
- Для элементов, написанных с помощью
camelCase
(или PascalCase
), можно вводить только инициалы. Например, asdc
найдёт AnotherSearchDemoComponent
.- Вы можете сузить поиск до определенных типов результатов:
f [строка]
ищет только файлыr [строка]
ищет в недавних файлахt [строка]
ищет в типахm [строка]
ищет в членах# [строка]
ищет в символахИсточник: https://michaelscodingspot.com/productivity-tips-in-visual-studio/
👍1
День пятьсот семьдесят третий. #ЗаметкиНаПолях
Класс Path
Многие разработчики до сих пор выделяют расширение файла из имени вручную, когда есть встроенный класс
Path.Combine
Этот метод принимает несколько строк пути и объединяет их в один путь. Обычно это делают, чтобы добавить имя файла к каталогу:
Path.GetTempFileName
Довольно часто бывает необходимо создать временный файл. Вам не важно имя или место хранения, вам просто нужно записать что-то в файл и через некоторое время прочитать оттуда. Можно написать этот код самостоятельно, но это будет утомительно и подвержено ошибкам.
Path.GetInvalidPathChars / Path.GetInvalidFileNameChars
Класс Path
Многие разработчики до сих пор выделяют расширение файла из имени вручную, когда есть встроенный класс
Path
, который имеет удобные методы, чтобы сделать это за вас. Класс находится в пространстве имен System.IO
и содержит множество полезных методов, которые сокращают объем стандартного кода, который вам приходится писать. Многим известны такие методы, как Path.GetFileName
и Path.GetExtension
, которые делают именно то, что вы ожидаете (извлекают имя файла и расширение соответственно). Рассмотрим несколько менее популярных.Path.Combine
Этот метод принимает несколько строк пути и объединяет их в один путь. Обычно это делают, чтобы добавить имя файла к каталогу:
directoryPath + "\" + filenameПроблема в том, что вы предполагаете, что разделителем каталогов в системе, в которой работает ваше приложение, является обратный слеш. Но в Unix используется прямой слеш. Это становится серьезной проблемой, поскольку .NET Core позволяет запускать приложения на большом количестве платформ.
Path.Combine
будет использовать разделитель каталогов, используемый в операционной системе, а также разберётся с избыточными разделителями (удалит дублирующие).Path.GetTempFileName
Довольно часто бывает необходимо создать временный файл. Вам не важно имя или место хранения, вам просто нужно записать что-то в файл и через некоторое время прочитать оттуда. Можно написать этот код самостоятельно, но это будет утомительно и подвержено ошибкам.
Path.GetTempFileName
не принимает никаких параметров, он создаёт пустой файл во временном каталоге пользователя, и возвращает вам полный его путь. Поскольку файл находится во временном каталоге пользователя, Windows автоматически удалит его при необходимости, и вам не придётся беспокоиться о засорении системы избыточными файлами.Path.GetInvalidPathChars / Path.GetInvalidFileNameChars
Path.GetInvalidPathChars
и его собрат Path.GetInvalidFileNameChars
возвращают массив всех символов, которые недопустимы для пути / имени файла в текущей системе. Я видел много кода, который вручную удаляет некоторые наиболее распространённые недопустимые символы, например, кавычки, но не удаляет другие недопустимые символы, что создаёт бомбу замедленного действия. И, если мы говорим о кросс-платформенности, неверно предполагать, что то, что недопустимо в одной системе, будет недопустимо в другой. Единственная проблема с этими методами в том, что они не позволяют проверить, содержит ли путь недопустимые символы. Из-за этого приходится писать подобные шаблонные методы: public static bool IsValidPath(string path) {Источник: https://chrisstclair.co.uk/6-lesser-known-features-of-c-net-that-you-should-be-using/
if (path == null)
throw new ArgumentNullException(nameof(path));
return path.IndexOfAny(Path.GetInvalidPathChars()) < 0;
}
👍1
.NET Разработчик
День пятьсот семьдесят первый. #ЗаметкиНаПолях Деревья выражений Деревья выражений - чрезвычайно мощная часть .NET, но они также являются одной из самых плохо понимаемых частей. По сути, они позволяют вам обернуть лямбда-выражения, такие как Func<T> или Action<T>…
День пятьсот семьдесят пятый. #ЧтоНовенького
Новые функции Visual Studio 2019 v16.8 Preview 2
Интеграция с Git
В некоторых репозиториях содержится более одного решения. Теперь, когда вы откроете такой репозиторий, в обозревателе решений отобразится список решений, из которых вы можете выбрать. См. рис. 1 ниже. По умолчанию вверху располагается пункт «Просмотр папки» (Folder View). Он откроет корневую папку репозитория. Двойной щелчок по одному из решений в списке откроет решение. Кроме того, вы можете использовать кнопку «Переключить представления» (Switch Views) на панели инструментов проводника решений, чтобы вернуться к списку представлений и легко переключаться между решениями в репозитории. Если в вашем репозитории только одно решение, Visual Studio покажет его, а если решений нет, откроется вид просмотра папки.
Повышение продуктивности в .NET
Visual Studio продолжает перенимать крутые фишки Rider'a. На этот раз добавили встроенные подсказки имён параметров перед каждым аргументом в вызовах функций. См. рис. 2 ниже. Чтобы получить доступ к этой функции, нужно включить её в Инструменты > Параметры > Текстовый редактор > C# > Дополнительно (Tools > Options > Text Editor > C# > Advanced) и выбрать «Показывать встроенные подсказки имён параметров» (Display inline parameter name hints).
Кроме того, теперь вы можете извлекать члены из выбранного класса в новый базовый класс с помощью нового вида рефакторинга «Выделить Базовый Класс» (Extract Base Class). Чтобы попробовать это, поместите курсор либо на имя класса, либо на выделенный член. Нажмите
Еще одна функция рефакторинга - преобразование
Источник: https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-8-preview-2/
Новые функции Visual Studio 2019 v16.8 Preview 2
Интеграция с Git
В некоторых репозиториях содержится более одного решения. Теперь, когда вы откроете такой репозиторий, в обозревателе решений отобразится список решений, из которых вы можете выбрать. См. рис. 1 ниже. По умолчанию вверху располагается пункт «Просмотр папки» (Folder View). Он откроет корневую папку репозитория. Двойной щелчок по одному из решений в списке откроет решение. Кроме того, вы можете использовать кнопку «Переключить представления» (Switch Views) на панели инструментов проводника решений, чтобы вернуться к списку представлений и легко переключаться между решениями в репозитории. Если в вашем репозитории только одно решение, Visual Studio покажет его, а если решений нет, откроется вид просмотра папки.
Повышение продуктивности в .NET
Visual Studio продолжает перенимать крутые фишки Rider'a. На этот раз добавили встроенные подсказки имён параметров перед каждым аргументом в вызовах функций. См. рис. 2 ниже. Чтобы получить доступ к этой функции, нужно включить её в Инструменты > Параметры > Текстовый редактор > C# > Дополнительно (Tools > Options > Text Editor > C# > Advanced) и выбрать «Показывать встроенные подсказки имён параметров» (Display inline parameter name hints).
Кроме того, теперь вы можете извлекать члены из выбранного класса в новый базовый класс с помощью нового вида рефакторинга «Выделить Базовый Класс» (Extract Base Class). Чтобы попробовать это, поместите курсор либо на имя класса, либо на выделенный член. Нажмите
Ctrl+.
, чтобы вызвать меню быстрых действий и рефакторинга. Оттуда выберите «Выделить член(ы) в новый базовый класс» (Pull member(s) up to new base class). Откроется новое диалоговое окно «Выделить Базовый Класс», в котором вы можете указать имя базового класса, место его размещения, выбрать элементы, которые хотите передать в новый базовый класс, и сделать их абстрактными, установив флажок в столбце «Сделать абстрактным» (Make abstract). См. рис. 3 ниже.Еще одна функция рефакторинга - преобразование
typeof
в nameof
. Использование nameof
вместо имени типа позволяет избежать использования рефлексии для извлечения объекта. Поместите курсор на выражение typeof(<QualifiedType>).Name
, нажмите Ctrl+.
и выберите «Преобразовать 'typeof' в 'nameof'» (Convert 'typeof' to 'nameof'). См. рис. 4 ниже. Источник: https://devblogs.microsoft.com/visualstudio/visual-studio-2019-v16-8-preview-2/
День пятьсот семьдесят шестой. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
57. Послание в Будущее
В течение многих лет я преподавала и работала бок о бок с программистами. И, возможно, поскольку большинство из них были умными людьми, мне всегда казалось, что они думали так: «Так как проблемы, с которыми они сталкивались, были трудными, то и решения должны быть так же сложны для понимания остальными (возможно, даже для самих себя через несколько месяцев после написания кода).»
Я помню один случай с Джо, студентом моего курса структур данных, который должен был зайти и показать мне, что он написал:
– Спорим, не сможете догадаться, что делает код! – с порога заявил он.
– Ты прав, – согласилась я, не тратя времени на разбор его кода, а думая, как донести до него важную мысль. – Я уверена, что ты много над этим работал. Но мне интересно, не забыл ли ты кое-что важное. Скажи-ка, Джо, у тебя ведь есть младший брат?
– Да, конечно! Фил. Он учится на вашем вводном курсе. Тоже учится программировать! – гордо ответил Джо.
– Замечательно, - сказала я. – Интересно, сможет ли он понять этот код.
– Ни за что! – сказал Джо. – Это сложно!
– А теперь представь себе, – предложила я, – что это настоящий рабочий код, и что через несколько лет Фил устроится на работу и получит задание его изменить. Что ты для него сделал?
Джо просто уставился на меня и моргал.
– Мы знаем, что Фил очень умный, верно? – Джо кивнул. – И я очень не люблю это говорить, но я тоже довольно умная! – Джо усмехнулся. – Так что, если я не могу быстро понять, что ты здесь сделал, то и твой очень умный младший брат, вероятно, будет ломать голову над этим.
Мне показалось, что Джо несколько иначе стал смотреть на свой код.
– Давай поступим так, – предложила я максимально дружелюбно. - Думай о каждой строке кода, которую ты пишешь, как о послании для кого-то в будущем. Кого-то, кто может оказаться твоим младшим братом. Представь, что ты объясняешь этому умному человеку, как решить эту трудную задачу.
Как ты себе это представляешь? Наверняка, что умный программист в будущем увидит твой код и скажет: «Вау! Это круто! Я прекрасно понимаю, что здесь происходит, и меня поражает, какой это элегантный и красивый фрагмент кода. Я хочу показать остальным в моей команде. Это шедевр!»
Джо, как ты думаешь, сможешь ли ты написать код, который решает эту сложную проблему, но будет настолько красив, что будет петь? Да, как навязчивая мелодия. Я думаю, что любой, кто может придумать очень сложное решение, как, например, твоё, также мог бы написать что-нибудь красивое. Хм… А может мне стоит ставить оценки за красоту? Что скажешь?
Джо взял свою работу и посмотрел на меня с легкой улыбкой:
– Я понял, профессор, я собираюсь сделать мир лучше для Фила. Спасибо.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Linda Rising.
97 Вещей, Которые Должен Знать Каждый Программист
57. Послание в Будущее
В течение многих лет я преподавала и работала бок о бок с программистами. И, возможно, поскольку большинство из них были умными людьми, мне всегда казалось, что они думали так: «Так как проблемы, с которыми они сталкивались, были трудными, то и решения должны быть так же сложны для понимания остальными (возможно, даже для самих себя через несколько месяцев после написания кода).»
Я помню один случай с Джо, студентом моего курса структур данных, который должен был зайти и показать мне, что он написал:
– Спорим, не сможете догадаться, что делает код! – с порога заявил он.
– Ты прав, – согласилась я, не тратя времени на разбор его кода, а думая, как донести до него важную мысль. – Я уверена, что ты много над этим работал. Но мне интересно, не забыл ли ты кое-что важное. Скажи-ка, Джо, у тебя ведь есть младший брат?
– Да, конечно! Фил. Он учится на вашем вводном курсе. Тоже учится программировать! – гордо ответил Джо.
– Замечательно, - сказала я. – Интересно, сможет ли он понять этот код.
– Ни за что! – сказал Джо. – Это сложно!
– А теперь представь себе, – предложила я, – что это настоящий рабочий код, и что через несколько лет Фил устроится на работу и получит задание его изменить. Что ты для него сделал?
Джо просто уставился на меня и моргал.
– Мы знаем, что Фил очень умный, верно? – Джо кивнул. – И я очень не люблю это говорить, но я тоже довольно умная! – Джо усмехнулся. – Так что, если я не могу быстро понять, что ты здесь сделал, то и твой очень умный младший брат, вероятно, будет ломать голову над этим.
Мне показалось, что Джо несколько иначе стал смотреть на свой код.
– Давай поступим так, – предложила я максимально дружелюбно. - Думай о каждой строке кода, которую ты пишешь, как о послании для кого-то в будущем. Кого-то, кто может оказаться твоим младшим братом. Представь, что ты объясняешь этому умному человеку, как решить эту трудную задачу.
Как ты себе это представляешь? Наверняка, что умный программист в будущем увидит твой код и скажет: «Вау! Это круто! Я прекрасно понимаю, что здесь происходит, и меня поражает, какой это элегантный и красивый фрагмент кода. Я хочу показать остальным в моей команде. Это шедевр!»
Джо, как ты думаешь, сможешь ли ты написать код, который решает эту сложную проблему, но будет настолько красив, что будет петь? Да, как навязчивая мелодия. Я думаю, что любой, кто может придумать очень сложное решение, как, например, твоё, также мог бы написать что-нибудь красивое. Хм… А может мне стоит ставить оценки за красоту? Что скажешь?
Джо взял свою работу и посмотрел на меня с легкой улыбкой:
– Я понял, профессор, я собираюсь сделать мир лучше для Фила. Спасибо.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Linda Rising.