مطالب
ویدیوهای آموزشی MVVM

یک سری ویدیوی رایگان آموزشی MVVM از مایکروسافت و همچنین شرکت Infragistics در دسترس هستند که جهت سهولت، لیست آن‌ها را ادامه می‌توانید مشاهده نمائید:


اشتراک‌ها
پیش نمایش JetBrains Fleet منتشر شد

Built from scratch, based on 20 years of experience developing IDEs. JetBrains Fleet uses the IntelliJ code-processing engine, with a distributed IDE architecture and a reimagined UI. 

پیش نمایش JetBrains Fleet منتشر شد
مطالب
Angular Material 6x - قسمت اول - افزودن آن به برنامه
کتابخانه‌ی Angular Material تعدادی کامپوننت زیبای با قابلیت استفاده‌ی مجدد، به خوبی آزمایش شده و با قابلیت دسترسی بالا را بر اساس الگوهای Material Design ارائه می‌دهد. برای توسعه دهندگان Angular، کتابخانه‌ی Angular Material پیاده سازی مرجع رهنمودهای طراحی متریال گوگل است که توسط تیم اصلی Angular پیاده سازی و توسعه داده می‌شود. در این سری، مفاهیم طراحی نگارش 6x این کتابخانه را به همراه نحوه‌ی برپایی و تنظیم آن و همچنین کار با کامپوننت‌های پیشرفته‌ی آن، بررسی خواهیم کرد.


منابع و مآخذ مرتبط با کتابخانه‌ی Angular Material

در اینجا مآخذ اصلی کار با این کتابخانه را ملاحظه می‌کنید که شامل اصول طراحی متریال و مخازن اصلی توسعه‌ی آن می‌باشند:
Material Design Specification
- https://material.io/design
Angular Material
- https://material.angular.io
- https://github.com/angular/material2


مفاهیم پایه‌ی طراحی متریال

چرا «زیبایی» رابط کاربری مهم است؟
در ابتدای معرفی کتابخانه‌ی Angular Material عنوان شد که این مجموعه به همراه تعدادی کامپوننت «زیبا» است. بنابراین این سؤال مطرح می‌شود که چرا و یا تا چه اندازه «زیبایی» رابط کاربری اهمیت دارد؟ مهم‌ترین دلیل آن بهبود تجربه‌ی کاربری است. بر اساس تحقیقاتی که بر روی کاربران بسیاری صورت گرفته‌است، مشخص شده‌است کاربران، با رابط‌های کاربری زیبا نتایج بهتری را از لحاظ کاهش زمان اتمام کار و تعداد خطاهای مرتبط دریافت می‌کنند.

اما ... طراحی برنامه‌های زیبا مشکل است. به همین جهت استفاده از کتابخانه‌های غنی مانند طراحی متریال که این امر را سهولت می‌بخشند، ضروری است. طراحی متریال یک زبان کامل طراحی برنامه‌های زیبا است. توسط گوگل طراحی شده‌است و دو هدف اصلی را دنبال می‌کند:
- وفاداری به اصول کلاسیک طراحی رابط کاربری
- ارائه‌ی تجربه‌ی کاربری یک‌دست و هماهنگ، در بین وسایل و اندازه‌های صفحات نمایشی مختلف

اصول پایه‌ی طراحی متریال نیز شامل موارد زیر است:
- «متریال» یک متافور است و بر اساس مطالعه‌ی نحوه‌ی کار با کاغذ، مرکب و ارتباط بین اشیاء در دنیای واقعی پدید آمد‌ه‌است.
- اشیاء در دنیای واقعی دارای ارتباط‌های ابعادی و حجمی هستند. برای مثال دو برگه‌ی کاغذ یک فضا را اشغال نمی‌کنند. طراحی متریال برای نمایش این ارتباط سه بعدی بین اشیاء، از نور و سایه استفاده می‌کند.
- در دنیای واقعی، اشیاء از درون یکدیگر رد نمی‌شوند. این مورد در طراحی متریال نیز صادق است.
- طراحی متریال به همراه جعبه‌ی رنگ مخصوص و بکارگیری فضاهای خالی و عناوین درشت بسیار مشخص، واضح و عمدی است.
- طراحی متریال به همراه حرکت و پویانمایی، جهت ارائه‌ی مفاهیم مختلف به کاربر، جهت درک بهتر او از برنامه است.


برپایی پیشنیازهای ابتدایی کار با Angular Material

پیش از ادامه‌ی بحث فرض بر این است که آخرین نگارش Angular CLI را نصب کرده‌اید و اگر پیشتر آن‌را نصب کرده‌اید، یکبار دستور ذیل را اجرا کنید تا تمام وابستگی‌های سراسری نصب شده‌ی در سیستم به صورت خودکار به روز رسانی شوند:
 npm update -g
سپس برنامه‌ی کلاینت Angular این سری را به همراه تنظیمات ابتدایی مسیریابی آن از طریق صدور فرمان ذیل آغاز می‌کنیم:
 ng new MaterialAngularClient --routing
پس از ایجاد ساختار اولیه‌ی برنامه و نصب خودکار وابستگی‌های آن، جهت آزمایش برنامه، به پوشه‌ی آن وارد شده و آن‌را اجرا می‌کنیم:
cd MaterialAngularClient
ng serve -o
که به این ترتیب برنامه در آدرس http://localhost:4200 و مرورگر پیش‌فرض سیستم نمایش داده خواهد شد.


افزودن کتابخانه‌ی Angular Material به برنامه

در طول این سری از سایت https://material.angular.io زیاد استفاده خواهیم کرد. همواره به روزترین روش افزودن کتابخانه‌ی Angular Material به یک برنامه‌ی موجود را در آدرس https://material.angular.io/guide/getting-started می‌توانید مشاهده کنید که خلاصه‌ی آن به صورت زیر است:
البته در Angular 6 روش تفصیلی نصب فوق که شامل 6 مرحله‌است، به صورت زیر هم خلاصه شده‌است:
 ng add @angular/material
متاسفانه در زمان نگارش این مطلب، نگارش 6.3.1 آن توسط دستور فوق نصب نشد و خطای «Error: Collection "@angular/material" cannot be resolved.» ظاهر گردید. البته روش رفع آن در اینجا بحث شده‌است که مهم نیست و در نگارش‌های رسمی بعدی حتما لحاظ خواهد شد. به همین جهت روش تفصیلی آن‌را که همیشه کار می‌کند، در ادامه پیگیری می‌کنیم. ابتدا بسته‌های ذیل را نصب کنید:
npm install --save @angular/material @angular/cdk
npm install --save @angular/animations
npm install --save hammerjs
- دستور اول  angular/cdk و angular/material را نصب می‌کند. cdk در اینجا به معنای کیت توسعه‌ی کامپوننت‌های Angular است که امکان استفاده‌ی از ویژگی‌های Angular Material را بدون الزامی به پیروی از زبان طراحی متریال، میسر می‌کند.
- همانطور که عنوان شد، طراحی متریال مبتنی بر حرکت و پویانمایی است. به همین جهت تعدادی از کامپوننت‌های آن نیاز به بسته‌ی angular/animations را دارند که توسط دستور دوم نصب می‌شود.
- دستور سوم نیز کامپوننت‌های slide و slider را پشتیبانی می‌کند (Gesture Support). البته پس نصب این وابستگی، نیاز است به فایل src/main.ts مراجعه کرده و یک سطر زیر را نیز افزود:
 import "hammerjs";
در ادامه پس از نصب بسته‌ی پویانمایی، به فایل app.module.ts مراجعه کرده و BrowserAnimationsModule را به لیست imports اضافه می‌کنیم:
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";

@NgModule({
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    AppRoutingModule
  ]
})
export class AppModule { }

مدیریت بهتر import کامپوننت‌های Angular Material

در ادامه به ازای هر کامپوننت Angular Material باید ماژول آن‌را به لیست imports افزود که پس از مدتی به یک فایل app.module.ts بسیار شلوغ خواهیم رسید. برای مدیریت بهتر این فایل، از روش مطرح شده‌ی در مطلب «سازماندهی برنامه‌های Angular» استفاده خواهیم کرد.
به همین جهت دو پوشه‌ی core و shared را درون پوشه‌ی src/app ایجاد می‌کنیم:


محتویات فایل src\app\core\core.module.ts به صورت زیر است:
import { CommonModule } from "@angular/common";
import { NgModule, Optional, SkipSelf } from "@angular/core";
import { RouterModule } from "@angular/router";


@NgModule({
  imports: [CommonModule, RouterModule],
  exports: [
    // components that are used in app.component.ts will be listed here.
  ],
  declarations: [
    // components that are used in app.component.ts will be listed here.
  ],
  providers: [
    /* ``No`` global singleton services of the whole app should be listed here anymore!
       Since they'll be already provided in AppModule using the `tree-shakable providers` of Angular 6.x+ (providedIn: 'root').
       This new feature allows cleaning up the providers section from the CoreModule.
       But if you want to provide something with an InjectionToken other that its class, you still have to use this section.
    */
  ]
})
export class CoreModule {
  constructor(@Optional() @SkipSelf() core: CoreModule) {
    if (core) {
      throw new Error("CoreModule should be imported ONLY in AppModule.");
    }
  }
}
در مورد جزئیات آن در مطلب «سازماندهی برنامه‌های Angular توسط ماژول‌ها» کاملا بحث شده‌است.
محتویات فایل src\app\shared\shared.module.ts نیز به صورت زیر است:
import { CommonModule } from "@angular/common";
import { HttpClientModule } from "@angular/common/http";
import { ModuleWithProviders, NgModule } from "@angular/core";
import { FormsModule } from "@angular/forms";

@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    HttpClientModule
  ],
  entryComponents: [
    // All components about to be loaded "dynamically" need to be declared in the entryComponents section.
  ],
  declarations: [
    // common and shared components/directives/pipes between more than one module and components will be listed here.
  ],
  exports: [
    // common and shared components/directives/pipes between more than one module and components will be listed here.
    CommonModule,
    FormsModule,
    HttpClientModule,
  ]
  /* No providers here! Since they’ll be already provided in AppModule. */
})
export class SharedModule {
  static forRoot(): ModuleWithProviders {
    // Forcing the whole app to use the returned providers from the AppModule only.
    return {
      ngModule: SharedModule,
      providers: [ /* All of your services here. It will hold the services needed by `itself`. */]
    };
  }
}
سپس تعاریف import این دو فایل را به فایل app.module.ts اضافه می‌کنیم:
import { CoreModule } from "./core/core.module";
import { SharedModule } from "./shared/shared.module";

@NgModule({
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    CoreModule,
    SharedModule.forRoot(),
    AppRoutingModule
  ]
})
export class AppModule { }
پس از این مقدمات، فایل جدید src\app\shared\material.module.ts را در پوشه‌ی shared ایجاد می‌کنیم تا بتوانیم مداخل کامپوننت‌های Angular Material را صرفا به آن اضافه کنیم؛ با این محتوا:
import { CdkTableModule } from "@angular/cdk/table";
import { NgModule } from "@angular/core";
import {
  MatAutocompleteModule,
  MatButtonModule,
  MatButtonToggleModule,
  MatCardModule,
  MatCheckboxModule,
  MatChipsModule,
  MatDatepickerModule,
  MatDialogModule,
  MatExpansionModule,
  MatFormFieldModule,
  MatGridListModule,
  MatIconModule,
  MatInputModule,
  MatListModule,
  MatMenuModule,
  MatNativeDateModule,
  MatPaginatorModule,
  MatProgressBarModule,
  MatProgressSpinnerModule,
  MatRadioModule,
  MatRippleModule,
  MatSelectModule,
  MatSidenavModule,
  MatSliderModule,
  MatSlideToggleModule,
  MatSnackBarModule,
  MatSortModule,
  MatStepperModule,
  MatTableModule,
  MatTabsModule,
  MatToolbarModule,
  MatTooltipModule,
} from "@angular/material";

@NgModule({
  imports: [
    MatAutocompleteModule,
    MatButtonModule,
    MatButtonToggleModule,
    MatCardModule,
    MatCheckboxModule,
    MatChipsModule,
    MatDatepickerModule,
    MatDialogModule,
    MatExpansionModule,
    MatFormFieldModule,
    MatGridListModule,
    MatIconModule,
    MatInputModule,
    MatListModule,
    MatMenuModule,
    MatNativeDateModule,
    MatPaginatorModule,
    MatProgressBarModule,
    MatProgressSpinnerModule,
    MatRadioModule,
    MatRippleModule,
    MatSelectModule,
    MatSidenavModule,
    MatSliderModule,
    MatSlideToggleModule,
    MatSnackBarModule,
    MatStepperModule,
    MatSortModule,
    MatTableModule,
    MatTabsModule,
    MatToolbarModule,
    MatTooltipModule,
    CdkTableModule
  ],
  exports: [
    MatAutocompleteModule,
    MatButtonModule,
    MatButtonToggleModule,
    MatCardModule,
    MatCheckboxModule,
    MatChipsModule,
    MatDatepickerModule,
    MatDialogModule,
    MatExpansionModule,
    MatGridListModule,
    MatIconModule,
    MatInputModule,
    MatListModule,
    MatMenuModule,
    MatNativeDateModule,
    MatPaginatorModule,
    MatProgressBarModule,
    MatProgressSpinnerModule,
    MatRadioModule,
    MatRippleModule,
    MatSelectModule,
    MatSidenavModule,
    MatSliderModule,
    MatSlideToggleModule,
    MatSnackBarModule,
    MatStepperModule,
    MatSortModule,
    MatTableModule,
    MatTabsModule,
    MatToolbarModule,
    MatTooltipModule,
    CdkTableModule
  ]
})
export class MaterialModule {
}
در اینجا هر کامپوننت مورد نیاز، به قسمت‌های import و exports اضافه شده‌اند.
سپس MaterialModule را نیز به قسمت‌های imports و exports فایل src\app\shared\shared.module.ts اضافه خواهیم کرد:
import { MaterialModule } from "./material.module";

@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    HttpClientModule,
    MaterialModule
  ],
  exports: [
    // common and shared components/directives/pipes between more than one module and components will be listed here.
    CommonModule,
    FormsModule,
    HttpClientModule,
    MaterialModule
  ]
})
export class SharedModule {
}
به این ترتیب در هر ماژول جدیدی که به برنامه اضافه شود و نیاز به کار با Angular Material را داشته باشد، تنها کافی است SharedModule را import کرد؛ مانند app.module.ts برنامه (البته بدون ذکر متد forRoot آن که این forRoot فقط محض ماژول اصلی برنامه است).

تا اینجا جهت اطمینان از اجرای برنامه، دستور ng serve -o را از ابتدا اجرا کنید.


افزودن چند کامپوننت مقدماتی متریال به برنامه

بهترین روش کار با این مجموعه، بررسی مستندات آن در سایت https://material.angular.io/components است. برای مثال برای افزودن دکمه، به مستندات آن مراجعه کرده و بر روی دکمه‌ی view source کلیک می‌کنیم:


سپس کدهای قسمت HTML آن‌را به برنامه و فایل app.component.html اضافه خواهیم کرد:
 <button mat-button>Click me!</button>
به همین ترتیب مستندات check box را یافته و آن‌را نیز اضافه می‌کنیم:
 <mat-checkbox>Check me!</mat-checkbox>
تا اینجا اگر برنامه را توسط دستور ng serve -o اجرا کنیم، یک چنین خروجی حاصل می‌شود:


البته شکل ظاهری آن‌ها تا اینجا آنچنان مطلوب نیست. برای رفع این مشکل، نیاز است یک قالب را به این کنترل‌ها و کامپوننت‌ها اعمال کرد. به همین جهت فایل styles.css واقع در ریشه‌ی برنامه را گشوده و قالب پیش‌فرض متریال را به آن اضافه می‌کنیم:
 @import "~@angular/material/prebuilt-themes/indigo-pink.css";
قالب‌های از پیش آماده‌ی متریال را در پوشه‌ی node_modules\@angular\material\prebuilt-themes می‌توانید مشاهده کنید.



پس از اعمال قالب، اکنون است که شکل ظاهری کنترل‌های آن بسیار بهتر شده‌اند و همچنین کار با آن‌ها به همراه پویانمایی نیز شده‌است:



افزودن آیکن‌های متریال به برنامه

مرحله‌ی آخر این تنظیمات، افزودن آیکن‌های متریال به برنامه‌است. برای این منظور فایل src\index.html را گشوده و یک سطر ذیل را به head اضافه کنید:
 <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
برای آزمایش آن، به فایل app.component.html مراجعه کرده و تعریف دکمه‌ای را که اضافه کردیم، به صورت ذیل با افزودن mat-icon تغییر می‌دهیم:
<button mat-button>
  <mat-icon>face</mat-icon>
  Click me!
</button>
<mat-checkbox>Check me!</mat-checkbox>
که این خروجی را تولید می‌کند:


لیست کامل این آیکن‌ها را به همراه توضیحات تکمیلی آن‌ها، در آدرس ذیل می‌توانید ملاحظه کنید:
http://google.github.io/material-design-icons

البته چون ما نمی‌خواهیم این آیکن‌ها را از وب بارگذاری کنیم، برای نصب محلی آن‌ها ابتدا دستور زیر را در ریشه‌ی پروژه صادر کنید:
 npm install material-design-icons --save
این آیکن فونت‌ها پس از نصب، در مسیر node_modules\material-design-icons\iconfont قابل مشاهده هستند:


همانطور که مشاهده می‌کنید، برای استفاده‌ی از این فایل‌های آیکن فونت محلی، تنها کافی است فایل material-icons.css را به برنامه معرفی کنیم. برای این منظور فایل angular.json را گشوده و قسمت styles آن‌را به صورت زیر تکمیل می‌کنیم:
"styles": [
   "node_modules/material-design-icons/iconfont/material-icons.css",
   "src/styles.css"
],
اکنون دیگر نیازی به ذکر link href اضافه شده‌ی به فایل src\index.html نداریم و باید از آن حذف شود.



کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید: MaterialAngularClient-01.zip
برای اجرای آن نیز ابتدا فایل restore.bat و سپس فایل ng-serve.bat را اجرا کنید.
مطالب
آشنایی با Fluent interfaces

تعریف مقدماتی fluent interface در ویکی پدیا به شرح زیر است: (+)

In software engineering, a fluent interface (as first coined by Eric Evans and Martin Fowler) is a way of implementing an object oriented API in a way that aims to provide for more readable code.

به صورت خلاصه هدف آن فراهم آوردن روشی است که بتوان متدها را زنجیر وار فراخوانی کرد و به این ترتیب خوانایی کد نوشته شده را بالا برد. پیاده سازی آن هم شامل دو نکته است:
الف) نوع متد تعریف شده باید مساوی با نام کلاس جاری باشد.
ب) در این حالت خروجی متد‌های ما کلمه کلیدی this خواهند بود.

برای مثال:
using System;

namespace FluentInt
{
public class FluentApiTest
{
private int _val;

public FluentApiTest Number(int val)
{
_val = val;
return this;
}

public FluentApiTest Abs()
{
_val = Math.Abs(_val);
return this;
}

public bool IsEqualTo(int val)
{
return val == _val;
}
}
}
مثالی هم از استفاده‌ی آن به صورت زیر می‌تواند باشد:
if (new FluentApiTest().Number(-10).Abs().IsEqualTo(10))
{
Console.WriteLine("Abs(-10)==10");
}
که در آن توانستیم تمام متدها را زنجیر وار و با خوانایی خوبی شبیه به نوشتن جملات انگلیسی در کنار هم قرار دهیم.
خوب! این مطلبی است که همه جا پیدا می‌کنید و مطلب جدیدی هم نیست. اما موردی را که سخت می‌شود یافت این است که طراحی کلاس فوق ایراد دارد. برای مثال شما می‌توانید ترکیب‌های زیر را هم تشکیل دهید و کار می‌کند؛ یا به عبارتی برنامه کامپایل می‌شود و این خوب نیست:
if(new FluentApiTest().Abs().Number(-10).IsEqualTo(10)) ...
if (new FluentApiTest().Abs().IsEqualTo(10)) ...
می‌شود در کدهای برنامه یک سری throw new exception را هم قرار داد که ... هی! اول باید اون رو فراخوانی کنی بعد این رو!
ولی ... این روش هم صحیح نیست. از ابتدای کار نباید بتوان متد بی‌ربطی را در طول این زنجیره مشاهده کرد. اگر قرار نیست استفاده گردد، نباید هم در intellisense ظاهر شود و پس از آن هم نباید قابل کامپایل باشد.

بنابراین صورت مساله به این ترتیب اصلاح می‌شود:
می‌خواهیم پس از نوشتن FluentApiTest و قرار دادن یک نقطه، در intellisense فقط Number ظاهر شود و نه هیچ متد دیگری. پس از ذکر متد Number فقط متد Abs یا مواردی شبیه به آن مانند Sqrt ظاهر شوند. پس از انتخاب مثلا Abs آنگاه متد IsEqualTo توسط Intellisense قابل دسترسی باشد. در روش اول فوق، به صورت دوستانه همه چیز در دسترس است و هر ترکیب قابل کامپایلی را می‌شود با متدها ساخت که این مورد نظر ما نیست.
اینبار پیاده سازی اولیه به شرح زیر تغییر خواهد کرد:
using System;

namespace FluentInt
{
public class FluentApiTest
{
public MathMethods<FluentApiTest> Number(int val)
{
return new MathMethods<FluentApiTest>(this, val);
}
}

public class MathMethods<TParent>
{
private int _val;
private readonly TParent _parent;

public MathMethods(TParent parent, int val)
{
_val = val;
_parent = parent;
}

public Restrictions<MathMethods<TParent>> Abs()
{
_val = Math.Abs(_val);
return new Restrictions<MathMethods<TParent>>(this, _val);
}
}

public class Restrictions<TParent>
{
private readonly int _val;
private readonly TParent _parent;

public Restrictions(TParent parent, int val)
{
_val = val;
_parent = parent;
}

public bool IsEqualTo(int val)
{
return _val == val;
}
}
}
در اینجا هم به همان کاربرد اولیه می‌رسیم:
if (new FluentApiTest().Number(-10).Abs().IsEqualTo(10))
{
Console.WriteLine("Abs(-10)==10");
}
با این تفاوت که intellisense هربار فقط یک متد مرتبط در طول زنجیره را نمایش می‌دهد و تمام متدها در همان ابتدای کار قابل انتخاب نیستند.
در پیاده سازی کلاس MathMethods از Generics استفاده شده به این جهت که بتوان نوع متد Number را بر همین اساس تعیین کرد تا متدهای کلاس MathMethods در Intellisense (یا به قولی در طول زنجیره مورد نظر) ظاهر شوند. کلاس Restrictions نیز به همین ترتیب معرفی شده است و از آن جهت تعریف نوع متد Abs استفاده کردیم. هر کلاس جدید در طول زنجیره، توسط سازنده خود به وهله‌ای از کلاس قبلی به همراه مقادیر پاس شده دسترسی خواهد داشت. به این ترتیب زنجیره‌ای را تشکیل داده‌ایم که سازمان یافته است و نمی‌توان در آن متدی را بی‌جهت پیش یا پس از دیگری صدا زد و همچنین دیگر نیازی به بررسی نحوه‌ی فراخوانی‌های یک مصرف کننده نیز نخواهد بود زیرا برنامه کامپایل نمی‌شود.
اشتراک‌ها
تفاوت‌های طراح ارشد و طراح تازه‌کار

در جامعه کاری که ما در اون قرار داریم، خیلی وقت‌ها تفاوت بین ادو مفهوم طراح ارشد (Senior Designer) و طراح تازه‌کار (Junior Designer) خیلی مشخص نیست و تعیین‌شون بعضا بواسطه تجربه و گاهی هم از طریق سمت‌هایی که در شرکت‌ها داده میشه، انجام می‌پذیره.

با در نظر گرفتن این موضوع که اخیرا مفهوم طراح، شکلی کلی‌تر به خودش گرفته و به طوری تغییر (و به دید من بهبود) پیدا کرده که معرف شخصی‌ست با نوع متفاوتی از تفکر در فهم یک مسئله و پیدا کردن راه حل اون. طراحان بسیاری هستند که علیرغم داشتن تجربه زیاد، اختیارات بالا و تاثیرگذاری در محصولات سازمان و همینطور تبحر استفاده از ابزارهای متنوع، همچنان تغییری در روند و نحوه تفکر اون‌ها برای طراحی محصولات ایجاد نشده.
 

تفاوت‌های طراح ارشد و طراح تازه‌کار
اشتراک‌ها
بررسی کنتراست رنگ

Color contrast checker
Check and suggests colors to meet the required WCAG or APCA contrast ratio.

بررسی کنتراست رنگ
اشتراک‌ها
الگوهای طراحی در Typescript
Here are the implementations of the following design patterns in TypeScript
Creational
Singleton
Abstract Factory
Factory Method
and ...
الگوهای طراحی در Typescript
اشتراک‌ها
پیاده سازی مفاهیم SOLID در ASP.NET Core توسط نویسنده‌ی AutoMapper

ASP.NET Core 1.0 is the ground-up rewrite of ASP.NET, MVC and Web API, bringing a new paradigm in building web applications and APIs in .NET. With this rewrite brought new techniques in building SOLID applications, and updated some existing patterns and tools.
In this session, we'll take a lap around some of the major extension points of ASP.NET Core 1.0, walking through how these features can help us build cleaner, more maintainable systems. We'll cover web APIs, traditional MVC applications, controllers, views, filters, dependency injection, tag helpers and more. With a SOLID foundation, our ASP.NET Core applications will be dead simple to build and maintain.
 

پیاده سازی مفاهیم SOLID در ASP.NET Core توسط نویسنده‌ی AutoMapper