نظرات مطالب
پَرباد - راهنمای اتصال و پیاده‌سازی درگاه‌های پرداخت اینترنتی (شبکه شتاب)
در مورد ثبت اطلاعات همونطور که دوستمون گفتن برای نمونه ثبت مشخصات بانک ملت مثال زده شده.
در مورد امنیت، این پروژه اوپن سورس هست لینک گیت هاب هم در توضیحات موجوده.
حتی در صورتیکه شخصی نسبت به امنیت اطلاعاتشون تردید داشته باشه، باید این رو در نظر داشته باشه که به هیچ وجه شخص دیگری با این اطلاعات کاری نمیتواند انجام دهد، به دو دلیل:
۱) کلیه عملیات بانکی فقط و فقط از جانب آی پی سرور یا وب سایت فروشنده (صاحب وب سایت) قابل دریافت هست که این آی پی در هنگام سفارش درگاه پرداخت توسط صاحب وب سایت، به بانک ارائه شده است.
۲) هیچ عملیاتی مانند انتقال وجه از یک حساب به حساب دیگه وجود نداره و این عملیات صرفا سه حالت اصلی و عمده، ثبت، تایید و برگشت هست.
اشتراک‌ها
معرفی Mapster

 Writing mapping method is machine job. Do not waste your time, let Mapster do it.

Benchmark 

معرفی Mapster
مطالب
Angular CLI - قسمت هفتم - اجرای آزمون‌ها
پروژه‌های Angular CLI در حالت پیش فرض آن‌ها به همراه دو نوع آزمون واحد و آزمون end to end ایجاد می‌شوند. Angular CLI از Karma برای اجرای آزمون‌های واحد استفاده می‌کند و از Protractor برای اجرای آزمون‌های end to end. برای شروع می‌توان از راهنمای آن کمک گرفت:
 > ng test --help
زمانیکه دستور ng test را اجرا می‌کنیم، به صورت خودکار تمام فایل‌های spec.ts.* را یافته و آزمون‌های واحد موجود در آن‌ها را اجرا می‌کند. این نوع فایل‌های ویژه نیز به صورت خودکار، زمانیکه اجزای مختلف Angular را توسط Angular CLI ایجاد می‌کنیم، تولید می‌شوند. به علاوه دستور ng test تغییرات این فایل‌ها را تحت نظر قرار داده و در صورت نیاز، آزمون‌های واحد را مجددا و به صورت خودکار اجرا می‌کند.


یک مثال: بررسی اجرای دستور ng test

یکی از مثال‌های بررسی شده‌ی در این سری را انتخاب و یا حتی یک برنامه‌ی جدید را توسط Angular CLI ایجاد کرده و سپس دستور ng test را در ریشه‌ی این پروژه اجرا کنید. به این ترتیب برنامه به صورت خودکار کامپایل شده و سپس به صورت خودکار آزمون‌های واحد آن‌را که در فایل‌های spec.ts‌.* قرار دارند، اجرا می‌کند. در آخر نتیجه را در مرورگر گزارش می‌دهد:


همانطور که مشخص است، 3 specs, 3 failures داریم. در اینجا می‌توان بر روی لینک Spec List کلیک کرد و لیست آزمون‌های واحد موجود را مشاهده نمود:


هر کدام از عناوین ذکر شده نیز به جزئیات مشکلات آن‌ها، لینک شده‌اند. برای مثال اگر بر روی اولین مورد کلیک کنیم، خطایی مانند «'alert' is not a known element» قابل مشاهده‌است. به این معنا که برای نمونه در قسمت قبل کامپوننت alert را به صفحه اضافه کردیم:
 <alert type="success">Alert success!</alert>
اما اجرا کننده‌ی آزمون‌های واحد اطلاعاتی در مورد آن ندارد؛ از این جهت که آزمون‌های واحد به صورت ایزوله فقط همان کامپوننت خاص برنامه را آزمایش می‌کنند و کاری به وابستگی‌های آن ندارد. به همین جهت فایل src\app\app.component.spec.ts را گشوده و تغییرات ذیل را به آن اعمال کنید:
import { NO_ERRORS_SCHEMA } from '@angular/core';

describe('AppComponent', () => {
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        AppComponent
      ],
  schemas: [NO_ERRORS_SCHEMA]
    }).compileComponents();
  }));
در اینجا ابتدا ماژول NO_ERRORS_SCHEMA معرفی شده و سپس به قسمت schemas معرفی گشته‌است.
پس از این تغییر، بلافاصله مجدد برنامه کامپایل شده و آزمون‌های واحد آن با موفقیت اجرا می‌شوند (با این فرض که هنوز پنجره‌ی اجرا کننده‌ی دستور ng test را باز نگه داشته‌اید):


تغییر افزودن schemas: [NO_ERRORS_SCHEMA] را باید در مورد تمام فایل‌های spec موجود تکرار کرد.


گزینه‌های مختلف دستور ng test

دستور ng test به همراه گزینه‌های متعددی است که شرح آن‌ها را در جدول ذیل مشاهده می‌کنید:

گزینه
 مخفف  توضیح
 code-coverage--  cc-   تولید گزارش code coverage که به صورت پیش فرض خاموش است. 
 colors--     به صورت پیش فرض فعال است و سبب نمایش رنگ‌های قرمز و سبز، برای آزمون‌های شکست خورده و یا موفق می‌شود. 
 single-run--  sr-   اجرای یکباره‌ی آزمون‌های واحد، بدون فعال سازی گزینه‌ی مشاهده‌ی مداوم تغییرات که به صورت پیش فرض خاموش است. 
 progress--     نمایش جزئیات کامپایل و اجرای آزمون‌های واحد که به صورت پیش فرض فعال است. 
 sourcemaps--  sm-   تولید فایل‌های سورس‌مپ که به صورت پیش فرض فعال است. 
 watch--
 w-   بررسی مداوم تغییرات فایل‌ها و اجرای آزمون‌های واحد به صورت خودکار که به صورت پیش فرض فعال است. 

بنابراین اجرا دستور ng test بدون ذکر هیچ گزینه‌ای به معنای اجرای مداوم آزمون‌های واحد، در صورت مشاهده‌ی تغییراتی در آن‌ها، به کمک Karma است.
همچنین دو دستور ذیل نیز به یک معنا هستند و هر دو سبب یکبار اجرای آزمون‌های واحد می‌شوند:
> ng test -sr
> ng test -w false


اجرای بررسی میزان پوشش آزمون‌های واحد

یکی از گزینه‌های ng test روشن کردن پرچم code-coverage است:
 > ng test --code-coverage
برای آزمایش آن دستور ذیل را در ریشه‌ی پروژه اجرا کنید (که سبب اجرای یکبار برررسی میزان پوشش آزمون‌های واحد می‌شود):
 > ng test -sr -cc
پس از اجرای این آزمون ویژه، پوشه‌ی جدیدی به نام coverage در ریشه‌ی پروژه‌ی جاری تشکیل می‌شود. فایل index.html آن‌را در مرورگر باز کنید تا بتوان گزارش تولید شده را مشاهده کرد:


کار این آزمون بررسی قسمت‌های مختلف برنامه و ارائه گزارشی است که مشخص می‌کند آیا آزمون‌های واحد نوشته شده تمام انشعابات برنامه را پوشش می‌دهند یا خیر؟ برای مثال اگر در متدی if/else دارید، آیا فقط قسمت if را پوشش داده‌اید و یا آیا قسمت else هم در آزمون‌های واحد، بررسی شده‌است.


اجرای آزمون‌های end to end

هدف از ساخت یک برنامه ... استفاده‌ی از آن توسط دیگران است؛ اینجا است که آزمون‌های end to end مفهوم پیدا می‌کنند. در آزمون‌های e2e رفتار برنامه همانند حالتی که یک کاربر از آن استفاده می‌کند، بررسی می‌شود (برای مثال باز کردن مرورگر، لاگین و مرور صفحات). برای این منظور، Angular CLI  در پشت صحنه از Protractor برای این نوع آزمون‌ها استفاده می‌کند.  
برای مشاهده‌ی راهنما و گزینه‌های مختلف مرتبط با آزمون‌های e2e، می‌توان دستور ذیل را صادر کرد:
 >ng e2e --help
البته با توجه به اینکه این دستور کار توزیع برنامه را نیز انجام می‌دهد، تمام گزینه‌های ng serve نیز در اینجا صادق هستند، به علاوه‌ی موارد ذیل:

 گزینه  مخفف توضیح
 config--  c-   به فایل کانفیگ آزمون‌های e2e اشاره می‌کند که به صورت پیش‌فرض همان protractor.conf.js واقع در ریشه‌ی پروژه‌است. 
 element-explorer--  ee-   بررسی و دیباگ protractor از طریق خط فرمان 
 serve--  s-   کامپایل و توزیع برنامه بر روی پورتی اتفاقی (حالت پیش فرض آن true است) 
 specs--  sp-   پیش فرض آن بررسی تمام specهای موجود در پروژ‌ه‌است. اگر نیاز به لغو آن باشد می‌توان از این گزینه استفاده کرد. 
 webdriver-update--  wu- به روز رسانی web driver که به صورت پیش فرض فعال است. 

بنابراین زمانیکه دستور ng e2e صادر می‌شود، به معنای کامپایل، توزیع برنامه بر روی پورتی اتفاقی و اجرای آزمون‌ها است.

از این جهت که این نوع آزمون‌ها، وابسته‌ی به جزئی خاص از برنامه نیستند، حالت عمومی داشته و فایل‌های spec آن‌ها را می‌توان در پوشه‌ی e2e واقع در ریشه‌ی پروژه، یافت. برای مثال در قسمتی از آن کار یافتن متن نمایش داده شده‌ی در صفحه‌ی اول سایت انجام می‌شود
getParagraphText() {
    return element(by.css('app-root h1')).getText();
}
و سپس در فایل spec آن بررسی می‌کند که آیا مساوی app works هست یا خیر؟
 expect(page.getParagraphText()).toEqual('app works!');

برای آزمایش آن دستور ng e2e را در ریشه‌ی پروژه صادر کنید. همچنین دقت داشته باشید که در این حالت نیاز است به اینترنت نیز متصل باشد؛ چون از chromedriver api گوگل نیز استفاده می‌کند. در غیراینصورت خطای ذیل را دریافت خواهید کرد:
 Error: getaddrinfo ENOTFOUND chromedriver.storage.googleapis.com chromedriver.storage.googleapis.com:443
مطالب
بررسی کارآیی کوئری‌ها در SQL Server - قسمت هشتم - بررسی عملگرهای Merge Join و Sort در یک Query Plan
در یک merge join، اطلاعات از دو ورودی مرتب شده، دریافت و join می‌شوند. اگر این ورودی‌ها از پیش مرتب شده نباشند (دارای ایندکس مناسبی نباشند)، یک عملگر Sort در این میان تزریق خواهد شد. عملگر Sort نیز اندکی متفاوت است از سایر عملگرها. این عملگر یک iterator نیست (یعنی ردیف به ردیف عمل نمی‌کند) و اگر اطلاعاتی وارد آن شد، ابتدا باید کل آن مرتب شود و سپس به قسمت‌های بعدی ارسال گردد؛ که مصرف حافظه و I/O زیادی را به همراه دارد. به همین جهت جزو مواردی است که باید در یک کوئری پلن، بیشتر به آن دقت داشت.


بررسی عملگر merge join

 ابتدا در management studio از منوی Query، گزینه‌ی Include actual execution plan را انتخاب می‌کنیم. سپس کوئری‌های زیر را اجرا می‌کنیم:
USE [WideWorldImporters];
GO

SET STATISTICS IO ON;
GO

SELECT
    [p].[PurchaseOrderID],
    [pl].[PurchaseOrderLineID]
FROM [Purchasing].[PurchaseOrders] [p]
    JOIN [Purchasing].[PurchaseOrderLines] [pl]
    ON [p].[PurchaseOrderID] = [pl].[PurchaseOrderID];
GO
در اینجا اطلاعات دو جدول PurchaseOrders و PurchaseOrderLines بر روی ستون PurchaseOrderID با هم Join شده‌اند و اجرای آن یک چنین کوئری پلنی را تولید می‌کند:


در اینجا یک merge join انجام شده، چون اطلاعات رسیده‌ی به آن، از پیش مرتب شده‌است. از این جهت که جدول PurchaseOrders دارای یک clustered index تعریف شده‌ی بر روی PurchaseOrderID است:
ALTER TABLE [Purchasing].[PurchaseOrders] ADD  CONSTRAINT [PK_Purchasing_PurchaseOrders] PRIMARY KEY CLUSTERED
(
   [PurchaseOrderID] ASC
)
و همچنین جدول PurchaseOrderLines نیز دارای یک non-clustered index تعریف شده‌ی بر روی PurchaseOrderID است:
CREATE NONCLUSTERED INDEX [FK_Purchasing_PurchaseOrderLines_PurchaseOrderID] ON [Purchasing].[PurchaseOrderLines]
(
    [PurchaseOrderID] ASC
)
چون این دو ایندکس پیش‌فرض، اطلاعات از پیش مرتب شده‌ای را بر اساس PurchaseOrderID دارند، قابلیت تغذیه‌ی merge join را خواهند داشت.

اما بهینه سازی کوئری‌های SQL Server، همیشه در یک چنین شرایطی، از merge join استفاده نمی‌کند. برای مثال کوئری زیر نیز دقیقا از لحاظ تعریف ایندکس بر روی OrderID، وضعیت مشابهی با کوئری قبلی دارد:
SELECT
    [o].[OrderID],
    [ol].[OrderLineID]
FROM [Sales].[Orders] [o]
    JOIN [Sales].[OrderLines] [ol]
    ON [o].[OrderID] = [ol].[OrderID];
GO
اما کوئری پلن آن به صورت زیر است:


اگر به میزان ضخامت پیکان‌های این پلن، با پلن قبلی دقت کنید، مشاهده می‌کنید که ضخامت آن‌ها در اینجا افزایش یافته‌است. این افزایش ضخامت پیکان‌ها، بیانگر افزایش میزان اطلاعات ارسالی به قسمت‌های مختلف است (حدود 231 هزار ردیف) به همراه اسکن بالایی بر روی ایندکس [FK_Sales_Orders_SalespersonPersonID] است (بر روی PersonID بجای OrderID) و دومی بر روی [NCCX_Sales_OrderLines]. چون ایندکس OrderID سنگین است و تعداد ردیف زیادی را شامل می‌شود، بهینه ساز ترجیح داده‌است تا از ایندکس دیگری استفاده کند که I/O کمتری را به همراه دارد. در این‌حالت دیگر merger join میسر نبوده و از hash match استفاده کرده‌است.

اگر OrderID انتخاب شده را از جدول OrderLines تهیه کنیم، چه اتفاقی رخ می‌دهد؟ (در کوئری قبلی، OrderID از جدول Orders انتخاب شده بود)
SELECT
    [ol].[OrderID],
    [ol].[OrderLineID]
FROM [Sales].[Orders] [o]
    JOIN [Sales].[OrderLines] [ol]
    ON [o].[OrderID] = [ol].[OrderID];
در این حالت به کوئری پلن زیر خواهیم رسید:


یک بازنویسی ساده و دریافت دو ستون از یک جدول سبب شده‌است تا بهینه سازی کوئری، join تشکیل شده را غیرضروری دانسته و مستقیم عمل کند.


اهمیت مرتب شده بودن اطلاعات در تشکیل Joinهای بهینه

کوئری زیر را در نظر بگیرید که در آن یک select * را داریم (که یک ضد الگو است):
SELECT *
FROM [Sales].[Orders] [o]
    JOIN [Sales].[OrderLines] [ol]
    ON [o].[OrderID] = [ol].[OrderID];
GO
اجرای آن چنین کوئری پلنی را تولید می‌کند:


جدول OrderLines دارای یک non-clustered index، فقط بر روی ستون OrderID است؛ اما با select * نوشته شده، تمام ستون‌های آن‌را درخواست کرده‌ایم (و نه فقط OrderID را)؛ به همین جهت اطلاعات آن پیش از ارسال به merge join باید توسط عملگر sort مرتب شود و همانطور که مشاهده می‌کنید، هزینه‌ی این عملگر در این پلن، 82 درصد کل است.


تاثیر order by بر روی کوئری پلن تشکیل شده

دو کوئری زیر را در نظر بگیرید که تفاوت دومی با اولی، در داشتن یک ORDER BY است:
SELECT TOP 1000
    *
FROM [Sales].[OrderLines];
GO

SELECT TOP 1000
    *
FROM [Sales].[OrderLines]
ORDER BY [Description];
GO
پس از اجرای این دو کوئری با هم، به کوئری پلن زیر خواهیم رسید:


اولی، تمام clustered index را اسکن نمی‌کند و جائیکه 1000 ردیف را از آن بازگشت می‌دهد، متوقف می‌شود.
اما در دومی چون نیاز به مرتب سازی اطلاعات بر اساس یک ستون بوده‌است، عملگر sort مشاهده می‌شود. اسکن آن نیز بر روی کل اطلاعات است (پیکان مرتبط با آن، نسبت به پلن قبلی ضخیم‌تر است) و سپس آن‌ها را مرتب می‌کند.

برای بهبود این وضعیت، تعداد ستون‌های بازگشت داده شده را محدود کرده و سپس بر اساس آن‌ها، ایندکس صحیحی را طراحی می‌کنیم:
بنابراین اینبار بجای select *، تعداد مشخصی از ستون‌ها را بازگشت می‌دهیم:
SELECT
    [CustomerID],
    [OrderDate],
    [ExpectedDeliveryDate]
FROM [Sales].[Orders]
ORDER BY [CustomerID];
GO
همچنین یک non-clustered index را بر روی CustomerID که دو ستون OrderDate و ExpectedDeliveryDate را include می‌کند، تعریف می‌کنیم:
CREATE NONCLUSTERED INDEX [IX_Sales_Orders_CustomerID_Dates]
ON [Sales].[Orders](
[CustomerID] ASC
)
INCLUDE (
[OrderDate], [ExpectedDeliveryDate]
)
ON [USERDATA];
GO
اکنون اگر کوئری جدید محدود شده را اجرا کنیم، به کوئری پلن زیر خواهیم رسید که در آن خبری از عملگر sort نیست؛ چون ایندکس جدید تعریف و استفاده شده، کار مرتب سازی را نیز انجام داده‌است:

اشتراک‌ها
Microsoft.Data.Sqlite 2.1 منتشر شد
// User-defined functions

connection.CreateFunction(
    "volume",
    (double radius, double height)
        => Math.PI * Math.Pow(radius, 2) * height);

// And use the function in SQL to find the biggest cylinder.

SELECT id, volume(radius, height) AS volume
FROM cylinder
ORDER BY volume DESC
LIMIT 1
Microsoft.Data.Sqlite 2.1 منتشر شد