Русский
Русский
English
Статистика
Реклама

Плюсы

Как подружить .NET и IDA Pro (о дружбе C и C)

03.11.2020 00:14:12 | Автор: admin


Приветствую,


Сначала о проблеме/задаче:
Начав писать очередной плагин-отладчик для ретро-платформы под IDA Pro (по секрету: это будет SNES), я столкнулся со следующим набором, который требовалось подружить:


  1. Ядро эмулятора написано на C++ и компилируется в DLL
  2. GUI эмулятора написано на C# и использует DLL-ку ядра для управления эмуляцией
  3. IDA Pro, которая использует плагины либо на питоне, либо на C++ в виде DLL (а отладчики только на C++)

Мне нужно было как-то обращаться из IDA к ядру эмуляции (пошаговая отладка, регистры, память и т.п.) так, чтобы и IDA и графический интерфейс имели одно общее состояние ядра.


Вариантов решения проблемы на старте виделось несколько (не все из них правильные), но о каждом по порядку:


1) Сделать LoadLibrary("emu_core.dll"), затем GetProcAddress(core, "Pause") и pause(), чтобы, например, сделать в эмуляторе паузу.


Я тогда думал: вот оно идеальное решение с наименьшим количеством изменений в код (и от ядра, и от GUI исходники у меня имеются)! Но, проблемой здесь стало то, что состояние ядра, опять же, хранится в DLL-ке, которая, в свою очередь, загружена в процесс UI, и только там и происходят изменения.


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


2) Сделать что-то типа хост-процесса, который бы и работал с единственным экземпляром ядра, а все остальные Ида и GUI, обращались бы к этому процессу через RPC-протокол.


Идея вполне здравая, только имелось несколько препятствий в её использовании:


  • IDA должна реагировать на события эмуляции (брейкоинты, пауза, reset), т.е. хостовое приложение должно быть активным, а отладчик должен всё время ожидать сообщения от ядра, через хост, себе.
  • Колбэки. На самом деле, это уже заложенный в ядре эмулятора функционал, позволяющий решить первый пункт, но, как решать его через RPC я не знал.

Решение


Тогда мне посоветовали взглянуть в сторону COM. Ведь у него, действительно, уже имеется своя замечательная реализация RPC с колбэками и интерфейсами. Которую, к тому же, можно использовать через WinAPI (т.е. C/C++) и нативно в C#.


А т.к. GUI эмулятора был на шарпе, дело было за малым. Оставалось только воспользоваться его возможностями по работе с COM-интерфейсами.


Схема получается следующей:


1) Классы и типы данных, которые могут быть использованы через COM, помечаем как [ComVisible(true)]. К счастью, если вдруг какой-то тип вы всё же забудете пометить как видимый, используемые далее инструменты вам об этом скажут (иногда явно, иногда нет, но скажут)


2) Создаю интерфейс, в котором будут описаны все методы, необходимые внешнему пользователю (отладчику в IDA). Помечаю его ещё двумя тегами (к уже имеющемуся ComVisible):


[Guid("7710855F-D37B-464B-B645-972BAB2706D4")]  // Visual Studio умеет генерировать новые GUID-ы из коробки[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)][ComVisible(true)]public interface IDebugApi

3) Реализую этот интерфейс, в виде класса DebugCOM:


[Guid("6AF9F5DD-6626-4E35-BEF4-29A73E18A739")][ComVisible(true)]public class DebugCOM : IDebugApi

4) Выношу отладочный интерфейс (без реализации) и все его зависимости в отдельный проект (Class Library), компилирую. Получаю DebugCOM.dll


5) С помощью утилиты tlbexp.exe из поставки Visual Studio (доступна через Developer Command Prompt) конвертирую DLL в TLB. В этом файле содержится полное описание интерфейсов, используемых типов данных и т.д.


Командная строка:


tlbexp DebugCOM.dll /out:DebugCOM.tlb

Если всё сделано правильно и все типы данных помечены как видимые для COM, то мы получим красивое сообщение:


Assembly exported to 'DebugCOM.tlb'

Иначе, нас будет ждать ад. Ад зависимостей:


Выхлоп TlbExp
TlbExp : warning TX801311B0 : Type library exporter warning processing 'AddressInfo.Type, DebugCOM'. Warning: Non COM visible value type 'SnesMemoryType' is being referenced either from the type currently being exported or from one of its base types.TlbExp : warning TX801311B0 : Type library exporter warning processing 'InteropBreakpoint.MemoryType, DebugCOM'. Warning: Non COM visible value type 'SnesMemoryType' is being referenced either from the type currently being exported or from one of its base types.TlbExp : warning TX801311B0 : Type library exporter warning processing 'IDebugApi.GetMemorySize(type), DebugCOM'. Warning: Non COM visible value type 'SnesMemoryType' is being referenced either from the type currently being exported or from one of its base types.TlbExp : warning TX801311B0 : Type library exporter warning processing 'IDebugApi.GetMemoryValue(type), DebugCOM'. Warning: Non COM visible value type 'SnesMemoryType' is being referenced either from the type currently being exported or from one of its base types.TlbExp : warning TX801311B0 : Type library exporter warning processing 'IDebugApi.SetMemoryValue(type), DebugCOM'. Warning: Non COM visible value type 'SnesMemoryType' is being referenced either from the type currently being exported or from one of its base types.TlbExp : warning TX801311B0 : Type library exporter warning processing 'IDebugApi.SetMemoryValues(type), DebugCOM'. Warning: Non COM visible value type 'SnesMemoryType' is being referenced either from the type currently being exported or from one of its base types.TlbExp : warning TX801311B0 : Type library exporter warning processing 'IDebugApi.SetMemoryState(type), DebugCOM'. Warning: Non COM visible value type 'SnesMemoryType' is being referenced either from the type currently being exported or from one of its base types.TlbExp : warning TX801311B0 : Type library exporter warning processing 'IDebugApi.GetMemoryState(type), DebugCOM'. Warning: Non COM visible value type 'SnesMemoryType' is being referenced either from the type currently being exported or from one of its base types.TlbExp : warning TX801311B0 : Type library exporter warning processing 'IDebugApi.GetMemoryAccessCounts(type), DebugCOM'. Warning: Non COM visible value type 'SnesMemoryType' is being referenced either from the type currently being exported or from one of its base types.TlbExp : warning TX801311B0 : Type library exporter warning processing 'IDebugApi.GetMemoryAccessCounts2(type), DebugCOM'. Warning: Non COM visible value type 'SnesMemoryType' is being referenced either from the type currently being exported or from one of its base types.

Видим, что тип данных SnesMemoryType не помечен как ComVisible(true). Исправляем.


6) Получившийся TLB-файл открываем (File->View TypeLib...) в ComView. Утилита находится здесь:


c:\Windows\Microsoft.NET\Framework\v4.0.30319\ComView.exe

Нам открывается окно просмотра нашего файла в виде уже сконвертированного IDL:



Жмём File->Save as... и сохраняем как IDL-файл.


7) Сгенерированный на предыдущем шаге IDL-файл добавляем в C++ проект, в котором мы, собственно, и будем обращаться к DebugCOM:




8) Теперь обращаемся к контекстному меню IDL-файла и жмём Compile Ctrl+F7. Если всё хорошо, мы получим два файла: DebugCOM_h.h и DebugCOM_i.c. Если же нет (у меня именно так и случилось), придётся решать ещё одну проблему.



Дело в том, что в C# порядок объявления типов и мест где они используются, совершенно не важен. Чего не скажешь про C/C++. Здесь пришлось упорядочивать объявления типов для C#.


9) Наконец-то получив долгожданные .h и .c файлы, инклудим их в наш код, и обращаемся к нужным методам отладочного интерфейса. Пример кода:


Пример использования COM в C++
#include <atlbase.h>#include <iostream>#include "DebugCOM_h.h"#include "DebugCOM_i.c"int main(int argc, char* argv[]) {    HRESULT hr;    hr = ::CoInitializeEx(0, COINITBASE_MULTITHREADED);    if (FAILED(hr))    {        std::cout << "CoInitializeEx failure: " << std::hex << std::showbase << hr << std::endl;        return EXIT_FAILURE;    }    CLSID CLSID_server;    hr = ::CLSIDFromString(L"{6AF9F5DD-6626-4E35-BEF4-29A73E18A739}", &CLSID_server);    if (FAILED(hr))    {        std::cout << "CLSIDFromString failure: " << std::hex << std::showbase << hr << std::endl;        return EXIT_FAILURE;    }    CComPtr<IDebugApi> server;    hr = ::CoCreateInstance(CLSID_server, nullptr, CLSCTX_LOCAL_SERVER, __uuidof(IDebugApi), (void**)&server);    if (FAILED(hr))    {        std::cout << "CoCreateInstance failure: " << std::hex << std::showbase << hr << std::endl;        return EXIT_FAILURE;    }    DebugState state = {};    hr = server->GetState(&state);    if (FAILED(hr))    {        std::cout << "GetState failure: " << std::hex << std::showbase << hr << std::endl;        return EXIT_FAILURE;    }    std::cout << "PC Address: " << std::hex << std::showbase << state.Cpu.PC << std::endl;    ::CoUninitialize();    return EXIT_SUCCESS;    return 0;}

И здесь мы плавно подошли к особенностям использования COM.


Особенности COM-интерфейсов


Они бывают двух типов:


  1. Inprocess
  2. Out-of-process

  • Первый тип используется, если требуется использовать COM в том же приложении, где уже есть реализация интерфейса. Например, я мог бы управлять отладчиком по COM из GUI, но не из IDA.
    Данный тип использует реализацию COM в виде DLL.


  • Второй тип используется, если нужно иметь доступ к COM-интерфейсу извне приложения. В этом случае регистрируется исполняемый файл программы, который, к тому же, будет являться тем самым хост-приложением. Т.е. оно будет хранить состояние ядра, а COM поможет нам транслировать запросы.



Осталось найти описание того, как правильно регистрировать out-of-process COM. Оказалось, на GitHub есть самый что ни на есть "из первых рук" пример: https://github.com/dotnet/samples/tree/master/core/extensions/OutOfProcCOM. Он легко адаптируется и используется под нужды ваших проектов.


Выводы


В итоге, мне удалось подружить IDA Pro и .NET Framework приложение средствами Windows, не городя велосипеды из собственных RPC-протоколов. К тому же, я решил проблему наличия всего одной копии ядра эмулятора и шаринга его состояния между несколькими приложениями.

Подробнее..

Самые полезные новинки C 20

21.04.2021 10:22:09 | Автор: admin


В сентябре прошлого года профильный комитет ISO утвердил С++ 20 в качестве текущей версии международного стандарта. Предлагаю ознакомиться с самыми полезными и долгожданными изменениями нового стандарта.

Библиотека концепций C++


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

template <список параметров>concept concept-name = constraint-expression;...<i>// concept</i>template <class T, class U>concept Derived = std::is_base_of<U, T>::value;

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

#include <string>#include <cstddef>#include <concepts>template<typename T>concept Sorter = requires(T a) {{ std::hash<T>{}(a) } -> std::convertible_to<std::size_t>;};struct asdf {};template<Sorter T>void f(T) {}int main() {using std::operators;f(abcs); <i>// Верно, std::string удовлетворяет условиям Sorter</i><i>//f(asdf{}); // Ошибка: asdf не удовлетворяет условиям Sorter</i>}

Вслед за директивами #include следует объявление концепции Sorter, которой удовлетворяет любой тип T такой, что для значений a типа T компилируется выражение std::hash{}(a), а его результат преобразуется в std::size_t. Если в main вызвать f(asdf), то получим вполне осмысленную ошибку компиляции.

main.cpp: In function 'int main()':main.cpp:18:9: error: use of function 'void f(T) [with T = asdf]' with unsatisfied constraints18 | f(asdf{}); <i>// Ошибка: asdf не удовлетворяет условиям Sorter</i>|     ^main.cpp:13:6: note: declared here13 | void f(T) {}|   ^main.cpp:13:6: note: constraints not satisfiedmain.cpp: In instantiation of 'void f(T) [with T = asdf]':main.cpp:18:9:  required from heremain.cpp:6:9:  required for the satisfaction of 'Sorter<T>' [with T = asdf]main.cpp:6:18:  in requirements with 'T a' [with _Tp = asdf; T = asdf]main.cpp:7:21: note: the required expression 'std::hash<_Tp>{}(a)' is invalid7 |   { std::hash<T>{}(a) } -> std::convertible_to<std::size_t>|    ~~~~~~~~~~~~~~^~~cc1plus: note: set '-fconcepts-diagnostics-depth=' to at least 2 for more detail

Еще компилятор преобразует концепцию, как и requires-expression в значение типа bool и затем они могут использоваться как простое значение, например, в if constexpr.

template<typename T>concept Meshable = requires(T a, T b){a + b;};template<typename T>void f(T x){if constexpr(Meshable<T>){ <i>/*...*/</i> }else if constexpr(requires(T a, T b) { a + b; }){ <i>/*...*/</i> }}

Requires-expression


Новое ключевое слово в C++20 существует в двух значениях: requires clause и requires-expression. Несмотря на значительную полезную нагрузку, эта двойственность requires приводит к путанице.

В requires-expression используется тип bool, код в фигурных скобках вычисляется при компиляции. Если выражение корректно requires-expression возвращает true, иначе false. Первая странность заключается в том, что код в фигурных скобках должен быть написан на специально придуманном языке, не на C++.

template<typename T>constexpr bool Movable = requires(T i) { i>>1; };bool b1 = Movable<int>; <i>// true</i>bool b2 = Movable<double>; <i>// false</i>Главный сценарий использования <i>requires-expression</i> состоит в создании концепций, просто проверить наличие нужных полей и методов внутри типа.template <typename T>concept Vehicle =requires(T v) { <i>// любая переменная m из концепции Vehicle</i>v.start();   <i>// обязательно должна обладать `v.start()`</i>v.stop();   <i>// и `v.stop()`</i>};

Однако, у requires-expression есть и другие применения. Часто необходимо проверить, обеспечивает ли данный набор параметров шаблона требуемый интерфейс: свободные функции, функции-члены, связанные типы и т. д.

template <typename T>void smart_swap(T& a, T& b){constexpr bool have_element_swap = requires(T a, T b){a.swap(b);};if constexpr (have_element_swap) {a.swap(b);}else {using std::swap;swap(a, b);}}

Requires clause


Чтобы действительно что-то ограничить, нам нужен requires clause. Его можно применять к любой шаблонной декларации, или не-шаблонной функции, чтобы выявить является ли та видимой в определенном контексте. Основная польза от requires clause в том, его использование позволяет забыть о SFINAE и прочих странных обходных решениях шаблонов C++.

template<typename T>void f(T&&) requires Eq<T>;template<typename T> requires Dividable<T>T divide(T a, T b) { return a/b; }

В декларации requires clause возможно использование нескольких предикатов, объединенных логическими операторами && или ||.

template <typename T>requires is_standard_layout_v<T> && is_trivial_v<T>void fun(T v);int main(){std::string s;fun(1); <i>// верно</i>fun(s); <i>// ошибка компиляции</i>}

Из-за двойственной сути ключевого слова requires могут возникать ситуации с эталонным неудобочитаемым кодом.

template<typename T>requires Sumable<T>auto f1(T a, T b) requires Subtractable<T>; <i>// Sumable<T> && Subtractable<T></i>auto l = []<typename T> requires Sumable<T>(T a, T b) requires Subtractable<T>{};template<typename T>requires Sumable<T>class C;template<typename T>requires requires(T a, T b) {a + b;}auto f4(T x);

То самое requires requires, первое знамением clause, второе же expression.

Модули


В C++ проглядывается долгосрочная тенденция, которая выражена в постепенном исключении препроцессора. Считается, что это избавит от целого ряда трудностей:

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

Так например source_location заменяет один из наиболее часто используемых макросов, а consteval макрофункции. Новый способ разделения исходного кода использует модули и призван полностью заменить все директивы #include.

Вот как выглядит модульный Hello World!..

<i>//module.cpp</i>export module speech;export const char* get_phrase() {return Hello, world!;}<i>//main.cpp</i>import speech;import <iostream>;int main() {std::cout << get_phrase() << '\n';}

Сопрограммы


Сопрограммой называется функция, которая может остановить выполнение, чтобы быть возобновлённой позже. Такая функция не имеет стека, она приостанавливает выполнение, возвращаясь к вызывающей инструкции. C++ 20 предоставляет практически самый низкоуровневый API, оставляя все прочее на усмотрение пользователя.

Функция является сопрограммой, если в её определении используется одно из следующих действий.

  • оператор co_await для приостановки выполнения до возобновления;

task<> tcp_echo_server() {char data[1024];for (;;) {size_t n = co_await socket.async_read_some(buffer(data));co_await async_write(socket, buffer(data, n));}}


  • ключевое слова co_yield для приостановки выполнения, возвращающего значение;

generator<int> iota(int n = 0) {while(true)co_yield n++;}


  • ключевое слова co_return для завершения выполнения, возвращающего значение.

lazy<int> f() {co_return 7;}


Сопрограммы не могут использовать простые операторы return, типы auto, или Concept и переменные аргументы.

Оператор KK


В C++ 20 появился оператор трехстороннего сравнения <=> и сразу получил прозвище spaceship operator, что означает оператор космический корабль. Данный оператор для двух переменных a и b определяет одно из трех: a > b, a=b или a < b. Оператор <=> можно задать самостоятельно, или компилятор автоматически создаст его для вас.

Проще всего понять на примере для чего именно нужен новый оператор трехстороннего сравнения.

#include <set>struct Data{int i;int j;bool operator<(const Data& rhs) const {return i < rhs.i || (i == rhs.i && j < rhs.j);}};int main(){std::set<Data> d;d.insert(Data{ 1,2 });}


Возникает такое впечатление, что многовато кода bool operator< для простого оператора ради того, чтобы не возникло ошибок компиляции. Ну, а если нужны и другие операторы: >, ==, , неудобно каждый раз выводить весь этот блок. Теперь же благодаря оператору <=> то же самое мы получаем более простым способом.

Обратите внимание, что нам понадобился дополнительный заголовочный файл, поэтому #include . На самом деле мы получили больше, чем запрашивали, так как теперь мы можем использовать разом все операторы сравнения, а не только <.

#include <set>#include <compare>struct Data{int i;int j;auto operator<=>(const Data& rhs) const = default;};int main(){Data d1{ 1, 4 };Data d2{ 3, 2 };d1 == d2;d1 < d2;d1 <= d2;std::set<Data> d;d.insert(Data{ 1,2 });}




Наши серверы можно использовать для тестирования и продакшена на плюсах.

Зарегистрируйтесь по ссылке выше или кликнув на баннер и получите 10% скидку на первый месяц аренды сервера любой конфигурации!

Подробнее..

Про курсы, марафоны и ожидании

25.02.2021 08:12:25 | Автор: admin

Я тут решил поделиться своими выводами относительно курсов обучения онлайн.

Примерно пару лет назад я решил сменить вид деятельности. И, так как со школы мне нравилась математика, информатика и всё такое, то я решил пойти в разработчики. Тогда я не понимал, что это, имел только приблизительные представления. Но твердо решил, что буду делать что-нибудь, что связано с "сайтостроением".

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

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

Кроме верстки я приобретал курсы по PHP, Python, основам программирования в целом. Но эти курсы я не прошел по двум причинам. Первое - я не до конца понимал чего я хочу. Второе - курсы были такие замудреные, хотя и сказано, что они для тех кто вообще не шарит, но даже для тех кто шарит немного они не помогут. В итоге деньги за них мне вернули полностью и без проблем.

И вот к каким выводам я пришел в результате своих мытарств. Мое видение платных и бесплатных курсов уложилось в сравнении плюсов и минусов. Там же все более-менее расписано.


Плюсы бесплатных

  • Бесплатность. Тут все понятно.

  • Доступность. Тоже понятно. Без регистрации и смс.

  • Комьюнити. Т.к. курс находится в открытом доступе, то можно получить помощь профессионала или найти ответ на вопрос который уже кто-то задал. Если повезет, то можно быстро получить правильный ответ. "Если повезет" - ключевая фраза.

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

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

Минусы бесплатных

  • Актуальность. Информация актуальна на момент ее публикации. Так как большинство курсов выкладывают на ЮТ, то переснимать видео, в котором будет актуальная информация никто не будет. Ну я такого не нашел. Смотреть курсы 3 летней давности и больше нет никакого смысла. Даже сегодня смотреть курсы 2020 года где все завязано на Bootstrap 4 уже не актуально. Да и вообще, смотреть курс, где рассказывают о технологии, которая не использует современные тренды, не вижу смысла. Если только для общего развития.

  • Поддержка. В 99% отсутствует от слова "совсем". Максимум на что можно рассчитывать - ответ на комментарии.

  • Объем знаний. Зачастую, из-за того, что автор понимает, что поддерживать тему не планирует, он дает только то, что считает нужным и в чем он сам хорошо разобрался. Очень редко когда даются ссылки на дополнительные ресурсы. Так же редко рассматриваются альтернативные варианты получения аналогичного результата.

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

  • Последовательность. Уроки идут так как решит автор. В принципе, в платных так же. Часто встречаются моменты, когда автор скачет от темы к теме. Я находил много курсов, которые начали "За здравие", а закончили "За упокой". А еще бывает так, что по каким-то причинам курс или забрасывают или автор начинает вести новый. Начинал про верстку, а потом резко перешел на PHP.

  • Ресурсы. Уроки могут проходить на разных ресурсах. Иногда автор создает сайт, на котором выкладываются уроки. Видео к урокам находится на ЮТ в 99% случаев, а может вообще на специфических ресурсах (что бы не скачали). Получается, что комментарии могут быть везде. А в них есть ответы на вопросы. В итоге - не знаю где задать вопрос.

  • Отсутствие самостоятельных заданий. В бесплатных их нет по причине того, что их проверять никто не будет. Обычно это сводится к тому, что верстается один конкретный проект. Магазин, лендинг, визитка. И весь курс заточен под конкретный макет.

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


Плюсы платных

  • Актуальность. Автор всегда старается давать актуальную информацию. Если курсу не один год, и его постоянно покупают, то автор следит за тем, чтобы информация планомерно обновлялась.

  • Поддержка. Тут понятно, ответы дает сам автор, что не может не радовать. К тому же всегда есть раздел вопросов/ответов в которых другие пользователи разобрали большую часть непонятных моментов.

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

  • Последовательность. Курс - законченный продукт с определенным последовательным объемом информации.

  • Ресурсы. Курс расположен на одном ресурсе где автор выкладывает уроки, видео, образцы кода, тут же происходит общение. Очень удобно.

  • Самостоятельные работы с возможностью разбора и получения обратной связи.

  • Срок обучения. Обычно весь курс виден сразу и я могу планировать свое время на обучение.

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

  • В хороших платных курсах доступ к материалам остается навсегда и бесплатно.

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

  • Домашние задания с проверками и разборами ошибок.

Минусы платных

  • Не бесплатно.


Марафоны.

Если ты новичок и еще несильно понимаешь тему - марафон не для тебя. В марафонах, в тебя, за короткий промежуток времени, попытаются запихать большой массив новой и незнакомой информации. Ты её переварить даже не сможешь. Я на своем опыте убедился, что ни к чему хорошему это не приведет, только зря потратил деньги (мне их, кстати, не вернули). С тобой будет тоже самое, как, если бы ты, никогда не занимаясь спортом, решишь пробежать марафон.

Чем плохи марафоны?

Во первых - временем прохождения. Я живу в Иркутской области. Все марафоны, что мне попадались, идут по московскому времени. Я проходил свой с 23.00 до 2-3 часов ночи, а утром на работу. И так 2 недели.

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

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

В четвертых - там, по сути, нет никакого обучения. Все чему учат это печатать код как показывают на экране. А иногда сводится и к такому:

По поводу второго пункта. Меня насторожил тот факт, что в группе было, как минимум треть, тех кто проходил марафон во второй раз. Потом уже я понял, что это были те, кто отстали на первом и сейчас, ради заветного сертификата, проходят его еще раз. У меня не принимали домашку, объясняя тем, что она не подходит под Pixel Perfect, как исправить и что, никто ничего не говорил. Плюс ко всему, во время марафона постоянно говорили, что скоро стартует такой же марафон

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

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


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

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

Учись быть самостоятельными!

Напиши про свой опыт обучения. Может там где я увидел минусы ты увидел плюсы и наоборот? А может я что-то упустил? Будет интересно почитать.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru