<?xml version="1.0" encoding="utf-8" ?><rss version="2.0" xmlns:tt="http://teletype.in/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Sofiya Yurova</title><generator>teletype.in</generator><description><![CDATA[Sofiya Yurova]]></description><image><url>https://teletype.in/files/11/11fe20b8-6686-4cdd-bca1-ba03bc0ed466.png</url><title>Sofiya Yurova</title><link>https://teletype.in/@sofiya-yurova</link></image><link>https://teletype.in/@sofiya-yurova?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=sofiya-yurova</link><atom:link rel="self" type="application/rss+xml" href="https://teletype.in/rss/sofiya-yurova?offset=0"></atom:link><atom:link rel="next" type="application/rss+xml" href="https://teletype.in/rss/sofiya-yurova?offset=10"></atom:link><atom:link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></atom:link><pubDate>Wed, 13 May 2026 23:34:16 GMT</pubDate><lastBuildDate>Wed, 13 May 2026 23:34:16 GMT</lastBuildDate><item><guid isPermaLink="true">https://teletype.in/@sofiya-yurova/B1koTNvjS</guid><link>https://teletype.in/@sofiya-yurova/B1koTNvjS?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=sofiya-yurova</link><comments>https://teletype.in/@sofiya-yurova/B1koTNvjS?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=sofiya-yurova#comments</comments><dc:creator>sofiya-yurova</dc:creator><title>Мини-руководство для начинающих</title><pubDate>Mon, 11 Nov 2019 19:59:19 GMT</pubDate><description><![CDATA[Создание REST API как микросервис Go вместе с MySQL.]]></description><content:encoded><![CDATA[
  <p>Создание REST API как микросервис Go вместе с MySQL.</p>
  <p><em>Настройка API</em><br />Первое, что нужно сделать, это выбрать пакет маршрутизации. Маршрутизация - это то, что связывает URL с исполняемой функцией. В данном руководстве импользуется mux, но есть и другие альтернативы без особой разницы в производительности, такие как httprouter и .</p>
  <p>Для простоты создадана одна конечная точка, которая печатает сообщение.</p>
  <p><code>package main</code></p>
  <p><code>import (<br />	&quot;log&quot;<br />	&quot;net/http&quot;</code></p>
  <p><code>	&quot;github.com/gorilla/mux&quot;<br />)</code></p>
  <p><code>func setupRouter(router *mux.Router) {<br />	router.<br />		Methods(&quot;POST&quot;).<br />		Path(&quot;/endpoint&quot;).<br />		HandlerFunc(postFunction)<br />}</code></p>
  <p><code>func postFunction(w http.ResponseWriter, r *http.Request) {<br />	log.Println(&quot;You called a thing!&quot;)<br />}</code></p>
  <p><code>func main() {<br />	router := mux.NewRouter().StrictSlash(true)</code></p>
  <p><code>	setupRouter(router)</code></p>
  <p><code>	log.Fatal(http.ListenAndServe(&quot;:8080&quot;, router))<br />}</code></p>
  <p><br />Приведенный выше код создает маршрутизатор, связывает URL-адрес с функцией-обработчиком, в данном случае postFunction, и запускает сервер на порту 8080, используя этот маршрутизатор.</p>
  <p><em>Подключение к базе данных</em><br />Go предоставляет интерфейс для баз данных SQL, но требует драйвера. Можно использовать go-sql-driver.</p>
  <p><code>package db</code></p>
  <p><code>import (<br />	&quot;database/sql&quot;</code></p>
  <p><code>	_ &quot;github.com/go-sql-driver/mysql&quot;<br />)</code></p>
  <p><code>func CreateDatabase() (*sql.DB, error) {<br />	serverName := &quot;localhost:3306&quot;<br />	user := &quot;myuser&quot;<br />	password := &quot;pw&quot;<br />	dbName := &quot;demo&quot;</code></p>
  <p><code>	connectionString := fmt.Sprintf(&quot;%s:%s@tcp(%s)/%s?charset=utf8mb4&amp;collation=utf8mb4_unicode_ci&amp;parseTime=true&amp;multiStatements=true&quot;, user, password, serverName, dbName)<br />	db, err := sql.Open(&quot;mysql&quot;, connectionString)<br />	if err != nil {<br />		return nil, err<br />	}</code></p>
  <p><code>	return db, nil<br />}</code><br /><br />Код помещается в другой пакет, называемый db, и предполагает, что на localhost:3306 работает база данных, называемая demo. База данных автоматически обрабатывает connection pool.</p>
  <p>Далее нужно обновить postFunction из предыдущего фрагмента кода, чтобы использовать эту базу данных.</p>
  <p><code>func postFunction(w http.ResponseWriter, r *http.Request) {<br />	database, err := db.CreateDatabase()<br />	if err != nil {<br />		log.Fatal(&quot;Database connection failed&quot;)<br />	}</code></p>
  <p><code>	_, err = database.Exec(&quot;INSERT INTO &#x60;test&#x60; (name) VALUES (&#x27;myname&#x27;)&quot;)<br />	if err != nil {<br />		log.Fatal(&quot;Database INSERT failed&quot;)<br />	}</code></p>
  <p><code>	log.Println(&quot;You called a thing!&quot;)<br />}</code><br /><br />Это довольно просто, но есть несколько проблем с приведенным выше кодом и несколько недостатков.</p>
  <p><em>Структуры и зависимости</em><br />Изучив приведенный выше код, можно заметить, что база данных открывается при каждом вызове API. Это неправильно, даже если открытая база данных безопасна для одновременного использования. Необходимо некоторое управление зависимостями, чтобы убедиться, что база данных открывается только один раз.</p>
  <p><code>package app</code></p>
  <p><code>import (<br />	&quot;database/sql&quot;<br />	&quot;log&quot;<br />	&quot;net/http&quot;</code></p>
  <p><code>	&quot;github.com/gorilla/mux&quot;<br />)</code></p>
  <p><code>type App struct {<br />	Router   *mux.Router<br />	Database *sql.DB<br />}</code></p>
  <p><code>func (app *App) SetupRouter() {<br />	app.Router.<br />		Methods(&quot;POST&quot;).<br />		Path(&quot;/endpoint&quot;).<br />		HandlerFunc(app.postFunction)<br />}</code></p>
  <p><code>func (app *App) postFunction(w http.ResponseWriter, r *http.Request) {<br />	_, err := app.Database.Exec(&quot;INSERT INTO &#x60;test&#x60; (name) VALUES (&#x27;myname&#x27;)&quot;)<br />	if err != nil {<br />		log.Fatal(&quot;Database INSERT failed&quot;)<br />	}</code></p>
  <p><code>	log.Println(&quot;You called a thing!&quot;)<br />	w.WriteHeader(http.StatusOK)<br />}</code><br /></p>
  <p>*****<br />Нужно начать с создания нового пакета, называемого app, для размещения структуры и ее методов. Структура приложения имеет два поля: маршрутизатор и база данных. В конце метода устанавливается код состояния.</p>
  <p>Основной пакет и функция также нуждаются в нескольких изменениях, чтобы использовать новую структуру App. Нужно удалить функции postFunction и setupRouter из этого пакета, поскольку они теперь находятся в пакете приложения. Остается следующее:</p>
  <p><code>package main</code></p>
  <p><code>import (<br />	&quot;log&quot;<br />	&quot;net/http&quot;</code></p>
  <p><code>	&quot;github.com/gorilla/mux&quot;<br />	&quot;github.com/johan-lejdung/go-microservice-api-guide/rest-api/app&quot;<br />	&quot;github.com/johan-lejdung/go-microservice-api-guide/rest-api/db&quot;<br />)</code></p>
  <p><code>func main() {<br />	database, err := db.CreateDatabase()<br />	if err != nil {<br />		log.Fatal(&quot;Database connection failed: %s&quot;, err.Error())<br />	}</code></p>
  <p><code>	app := &amp;app.App{<br />		Router:   mux.NewRouter().StrictSlash(true),<br />		Database: database,<br />	}</code></p>
  <p><code>	app.SetupRouter()</code></p>
  <p><code>	log.Fatal(http.ListenAndServe(&quot;:8080&quot;, app.Router))<br />}</code><br /><br />Чтобы использовать новую структуру, нужно открыть базу данных и новый маршрутизатор. Затем необходимо вставить их оба в поля новой структуры App.</p>
  <p>Теперь с базой данных есть соединение, которое будет использоваться одновременно во всех входящих вызовах API.</p>
  <p>В качестве последнего шага следует добавить GET-Metod в настройку маршрутизатора и вернуть данные в формате JSON. Начать стоит с добавления структуры, чтобы заполнить данные, и отображения поля в JSON.</p>
  <p><code>package app</code></p>
  <p><code>import (<br />	&quot;time&quot;<br />)</code></p>
  <p><code>type DbData struct {<br />	ID   int       &#x60;json:&quot;id&quot;&#x60;<br />	Date time.Time &#x60;json:&quot;date&quot;&#x60;<br />	Name string    &#x60;json:&quot;name&quot;&#x60;<br />}<br /></code></p>
  <p>С расширением app.go файла, с новым методом getFunction, который извлекает и записывает данные в ответ клиента, окончательный файл выглядит следующим образом:</p>
  <p><br /><code>package app</code></p>
  <p><code>import (<br />	&quot;database/sql&quot;<br />	&quot;encoding/json&quot;<br />	&quot;log&quot;<br />	&quot;net/http&quot;</code></p>
  <p><code>	&quot;github.com/gorilla/mux&quot;<br />)</code></p>
  <p><code>type App struct {<br />	Router   *mux.Router<br />	Database *sql.DB<br />}</code></p>
  <p><code>func (app *App) SetupRouter() {<br />	app.Router.<br />		Methods(&quot;GET&quot;).<br />		Path(&quot;/endpoint/{id}&quot;).<br />		HandlerFunc(app.getFunction)</code></p>
  <p><code>	app.Router.<br />		Methods(&quot;POST&quot;).<br />		Path(&quot;/endpoint&quot;).<br />		HandlerFunc(app.postFunction)<br />}</code></p>
  <p><code>func (app *App) getFunction(w http.ResponseWriter, r *http.Request) {<br />	vars := mux.Vars(r)<br />	id, ok := vars[&quot;id&quot;]<br />	if !ok {<br />		log.Fatal(&quot;No ID in the path&quot;)<br />	}</code></p>
  <p><code>	dbdata := &amp;DbData{}<br />	err := app.Database.QueryRow(&quot;SELECT id, date, name FROM &#x60;test&#x60; WHERE id = ?&quot;, id).Scan(&amp;dbdata.ID, &amp;dbdata.Date, &amp;dbdata.Name)<br />	if err != nil {<br />		log.Fatal(&quot;Database SELECT failed&quot;)<br />	}</code></p>
  <p><code>	log.Println(&quot;You fetched a thing!&quot;)<br />	w.WriteHeader(http.StatusOK)<br />	if err := json.NewEncoder(w).Encode(dbdata); err != nil {<br />		panic(err)<br />	}<br />}</code></p>
  <p><code>func (app *App) postFunction(w http.ResponseWriter, r *http.Request) {<br />	_, err := app.Database.Exec(&quot;INSERT INTO &#x60;test&#x60; (name) VALUES (&#x27;myname&#x27;)&quot;)<br />	if err != nil {<br />		log.Fatal(&quot;Database INSERT failed&quot;)<br />	}</code></p>
  <p><code>	log.Println(&quot;You called a thing!&quot;)<br />	w.WriteHeader(http.StatusOK)<br />}</code></p>
  <p><em>Миграция базы данных</em><br />Окончательное дополнение к проекту. Когда база данных уже тесно связана с приложением или службой, можно избавиться от непостижимых головных болей, правильно обрабатывая миграции этой базы данных. Следующим шагом будет использование миграции для этого и расширение <code>package db</code> .</p>
  <p><code>package db</code></p>
  <p><code>import (<br />	&quot;database/sql&quot;<br />	&quot;fmt&quot;<br />	&quot;log&quot;<br />	&quot;os&quot;</code></p>
  <p><code>	_ &quot;github.com/go-sql-driver/mysql&quot;<br />	&quot;github.com/golang-migrate/migrate&quot;<br />	&quot;github.com/golang-migrate/migrate/database/mysql&quot;<br />	_ &quot;github.com/golang-migrate/migrate/source/file&quot;<br />)</code></p>
  <p><code>func CreateDatabase() (*sql.DB, error) {<br />	// I shortened the code here. Here is where the DB setup were made.<br />	// In order to save some space I&#x27;ve removed the connection setup, but it can<br />	// be seen here: https://gist.github.com/johan-lejdung/ecea9dab9b9621d0ceb054cec70ae676#file-database_connect-go</code></p>
  <p><code>	if err := migrateDatabase(db); err != nil {<br />		return db, err<br />	}</code></p>
  <p><code>	return db, nil<br />}</code></p>
  <p><code>func migrateDatabase(db *sql.DB) error {<br />	driver, err := mysql.WithInstance(db, &amp;mysql.Config{})<br />	if err != nil {<br />		return err<br />	}</code></p>
  <p><code>	dir, err := os.Getwd()<br />	if err != nil {<br />		log.Fatal(err)<br />	}</code></p>
  <p><code>	migration, err := migrate.NewWithDatabaseInstance(<br />		fmt.Sprintf(&quot;file://%s/db/migrations&quot;, dir),<br />		&quot;mysql&quot;,<br />		driver,<br />	)<br />	if err != nil {<br />		return err<br />	}</code></p>
  <p><code>	migration.Log = &amp;MigrationLogger{}</code></p>
  <p><code>	migration.Log.Printf(&quot;Applying database migrations&quot;)<br />	err = migration.Up()<br />	if err != nil &amp;&amp; err != migrate.ErrNoChange {<br />		return err<br />	}</code></p>
  <p><code>	version, _, err := migration.Version()<br />	if err != nil {<br />		return err<br />	}</code></p>
  <p><code>	migration.Log.Printf(&quot;Active database version: %d&quot;, version)</code></p>
  <p><code>	return nil<br />}</code></p>
  <p>Сразу после открытия базы данных добавляется еще один вызов функции в migrateDatabase. Затем вставляется структура MigrationLogger для обработки журналов во время процесса. Миграции выполняются из обычных sql-запросов. Файлы миграции считываются из папки.</p>
  <p>Каждый раз, когда база данных открыта, будут применены все непримененные миграции базы данных. Тем самым поддерживая базу данных в актуальном состоянии без какого-либо вмешательства со стороны.</p>
  <p>Это в сочетании с файлом docker-compose, содержащим базу данных, делает разработку на нескольких машинах чрезвычайно простой.</p>
  <p>Нерасполагаемый микросервис бесполезен, поэтому нужно добавить Dockerfile, чтобы упаковать приложение для удобного распространения</p>
  <p><code>FROM golang:1.11 as builder<br />WORKDIR $GOPATH/src/github.com/johan-lejdung/go-microservice-api-guide/rest-api<br />COPY ./ .<br />RUN GOOS=linux GOARCH=386 go build -ldflags=&quot;-w -s&quot; -v<br />RUN cp rest-api /</code></p>
  <p><code>FROM alpine:latest<br />COPY --from=builder /rest-api /<br />CMD [&quot;/rest-api&quot;]</code></p>
  <p><br /><a href="https://dev.to/johanlejdung/a-mini-guide-build-a-rest-api-as-a-go-microservice-together-with-mysql-27m2?utm_source=dormosheio&utm_campaign=dormosheio" target="_blank">Оригинал можно посмотреть тут.</a></p>
  <p><a href="https://github.com/johan-lejdung/go-microservice-api-guide" target="_blank">Код на github</a>.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@sofiya-yurova/HyagapUoB</guid><link>https://teletype.in/@sofiya-yurova/HyagapUoB?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=sofiya-yurova</link><comments>https://teletype.in/@sofiya-yurova/HyagapUoB?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=sofiya-yurova#comments</comments><dc:creator>sofiya-yurova</dc:creator><title>Web Assembly: что это вообще такое и с чем его едят?</title><pubDate>Mon, 11 Nov 2019 11:58:44 GMT</pubDate><description><![CDATA[Web Assembly поддерживается всеми основными браузерами и обеспечивает некоторые преимущества в производительности по сравнению с JavaScript. Веб-сборка имеет большой потенциал и поддержку.]]></description><content:encoded><![CDATA[
  <p><em>Web Assembly поддерживается всеми основными браузерами и обеспечивает некоторые преимущества в производительности по сравнению с JavaScript. Веб-сборка имеет большой потенциал и поддержку.</em></p>
  <p><em>Что такое веб-сборка?</em></p>
  <p>Web Assembly — это спецификация для виртуальной машины, которая работает в браузере. По сравнению с высокодинамичной веб-сборкой JavaScript можно добиться гораздо более высокой производительности. Вопреки распространенному заблуждению, хотя Web Assembly не полностью заменяет JavaScript. </p>
  <p>Веб-сборка основана на LLVM (низкоуровневая виртуальная машина), на которую могут ориентироваться компиляторы. Если кто-то хочет создать новый язык программирования, у него может быть компилятор для его языка, создающий код LLVM, а затем можно использовать уже существующую цепочку инструментов, чтобы скомпилировать его для конкретного кода платформы. Человеку, создающему компилятор для нового языка, не нужно было бы создавать совершенно разные системы для разных архитектур ЦП. Web Assembly, основанная на LLVM, может запускать код, написанный на разных языках.</p>
  <p>Пока еще не поддерживается сборка мусора, что ограничивает языки, на которые она нацелена в настоящее время. C/C++, C# и Rust — это несколько языков, которые на сегодняшний день могут использоваться с веб-сборкой, но в будущем ожидается больше.</p>
  <p><em>Какие другие языки можно использовать?</em></p>
  <p>C/C++, C#/.Net, Elixir, Go, Java, Python, Rust.</p>
  <p><em>Зачем использовать веб-сборку?</em></p>
  <p>Web Assembly в первую очередь можно использовать для повышения производительности в вычислительно дорогих операциях. Используемый двоичный формат гораздо более строг, чем JavaScript, и он больше подходит для вычислительных операций. Существует также много существующего и проверенного кода для работы, такого как криптография или видеодекодеры, который существует в C/C++, который можно использовать на странице. Несмотря на всю свою гибкость, интерпретируемый код JavaScript работает не так быстро, как собственный двоичный файл. Для некоторых типов приложений эта разница в производительности не важна (например, в текстовом редакторе). Для других приложений различия в производительности приводят к различиям в опыте.</p>
  <p>Хотя спрос на производительность является мотивацией для создания собственного двоичного файла, существуют также соображения безопасности. Собственные двоичные файлы могут иметь доступ к большему количеству системных ресурсов, чем реализованное в сети решение. Также важна забота о том, чтобы программа (особенно если она от третьей стороны) не делала ничего вредоносного или не получала доступ к ресурсам без разрешения. Веб-сборка помогает преодолеть разрыв между этими двумя потребностями. Это обеспечивает более высокую производительность среды.</p>
  <p><em>C++? Разве этим не переполнится буфер?</em></p>
  <p>Конечно. Но только в пределах песочницы, в которой будет выполняться код. Это может привести к сбою программы, но не может вызвать произвольное выполнение кода вне песочницы.<br />В настоящее время Web Assembly не имеет никаких привязок к Host API. Когда кто-то ориентируется на веб-сборку, у него нет среды, позволяющей обойти ограничения безопасности, в которых будет выполняться код JavaScript. Нет прямого доступа к файловой системе, нет доступа к памяти вне программы, есть ограниченность в общении с WebSockets и HTTP-запросом, который не нарушает ограничения CORS.</p>
  <p><a href="https://www.codeproject.com/Articles/5250727/Introduction-to-Web-Assembly-with-C-Cplusplus" target="_blank">Оригинал и пример использования тут.</a></p>

]]></content:encoded></item></channel></rss>